wined3d: Use separate structures for ddraw style strided data and wined3d's internal...
[wine/multimedia.git] / dlls / wined3d / device.c
blob70e6f6332d1467ee2d444d910e335c3e26413c14
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-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 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 IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
69 return GL_POINTS;
71 case WINED3DPT_LINELIST:
72 return GL_LINES;
74 case WINED3DPT_LINESTRIP:
75 return GL_LINE_STRIP;
77 case WINED3DPT_TRIANGLELIST:
78 return GL_TRIANGLES;
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
98 default:
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
100 return GL_NONE;
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
108 case GL_POINTS:
109 return WINED3DPT_POINTLIST;
111 case GL_LINES:
112 return WINED3DPT_LINELIST;
114 case GL_LINE_STRIP:
115 return WINED3DPT_LINESTRIP;
117 case GL_TRIANGLES:
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
138 default:
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
144 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
146 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
147 *regnum = WINED3D_FFP_POSITION;
148 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
149 *regnum = WINED3D_FFP_BLENDWEIGHT;
150 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
151 *regnum = WINED3D_FFP_BLENDINDICES;
152 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
153 *regnum = WINED3D_FFP_NORMAL;
154 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
155 *regnum = WINED3D_FFP_PSIZE;
156 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
157 *regnum = WINED3D_FFP_DIFFUSE;
158 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
159 *regnum = WINED3D_FFP_SPECULAR;
160 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
161 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
162 else
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
165 *regnum = ~0U;
166 return FALSE;
169 return TRUE;
172 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
173 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
175 /* We need to deal with frequency data! */
176 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
177 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
178 const DWORD *streams = declaration->streams;
179 unsigned int i;
181 memset(stream_info, 0, sizeof(*stream_info));
183 /* Check for transformed vertices, disable vertex shader if present. */
184 stream_info->position_transformed = declaration->position_transformed;
185 if (declaration->position_transformed) use_vshader = FALSE;
187 /* Translate the declaration into strided data. */
188 for (i = 0; i < declaration->declarationWNumElements - 1; ++i)
190 const WINED3DVERTEXELEMENT *element = declaration->pDeclarationWine + i;
191 GLuint buffer_object = 0;
192 const BYTE *data = NULL;
193 BOOL stride_used;
194 unsigned int idx;
195 DWORD stride;
197 TRACE("%p Element %p (%u of %u)\n", declaration->pDeclarationWine,
198 element, i + 1, declaration->declarationWNumElements - 1);
200 if (!This->stateBlock->streamSource[element->Stream]) continue;
202 stride = This->stateBlock->streamStride[element->Stream];
203 if (This->stateBlock->streamIsUP)
205 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
206 buffer_object = 0;
207 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
209 else
211 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
212 data = buffer_get_memory(This->stateBlock->streamSource[element->Stream], 0, &buffer_object);
214 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
215 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
216 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
217 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
218 * not, drawStridedSlow is needed, including a vertex buffer path. */
219 if (This->stateBlock->loadBaseVertexIndex < 0)
221 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
222 buffer_object = 0;
223 data = ((struct wined3d_buffer *)This->stateBlock->streamSource[element->Stream])->resource.allocatedMemory;
224 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
226 FIXME("System memory vertex data load offset is negative!\n");
230 if (fixup)
232 if (buffer_object) *fixup = TRUE;
233 else if (*fixup && !use_vshader
234 && (element->Usage == WINED3DDECLUSAGE_COLOR
235 || element->Usage == WINED3DDECLUSAGE_POSITIONT))
237 static BOOL warned = FALSE;
238 if (!warned)
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
242 warned = TRUE;
247 data += element->Offset;
249 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
251 if (use_vshader)
253 stride_used = vshader_get_input(This->stateBlock->vertexShader, element->Usage, element->UsageIndex, &idx);
255 else
257 if (!declaration->ffp_valid[i])
259 WARN("Skipping unsupported fixed function element of type %s and usage %s\n",
260 debug_d3ddecltype(element->Type), debug_d3ddeclusage(element->Usage));
261 stride_used = FALSE;
263 else
265 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
269 if (stride_used)
271 TRACE("Load %s array %u [usage %s, usage_idx %u, "
272 "stream %u, offset %u, stride %u, type %s, buffer_object %u]\n",
273 use_vshader ? "shader": "fixed function", idx,
274 debug_d3ddeclusage(element->Usage), element->UsageIndex,
275 element->Stream, element->Offset, stride, debug_d3ddecltype(element->Type), buffer_object);
277 stream_info->elements[idx].d3d_type = element->Type;
278 stream_info->elements[idx].size = WINED3D_ATR_SIZE(element->Type);
279 stream_info->elements[idx].format = WINED3D_ATR_FORMAT(element->Type);
280 stream_info->elements[idx].type = WINED3D_ATR_GLTYPE(element->Type);
281 stream_info->elements[idx].stride = stride;
282 stream_info->elements[idx].normalized = WINED3D_ATR_NORMALIZED(element->Type);
283 stream_info->elements[idx].data = data;
284 stream_info->elements[idx].type_size = WINED3D_ATR_TYPESIZE(element->Type);
285 stream_info->elements[idx].stream_idx = element->Stream;
286 stream_info->elements[idx].buffer_object = buffer_object;
288 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->Type == WINED3DDECLTYPE_D3DCOLOR)
290 stream_info->swizzle_map |= 1 << idx;
292 stream_info->use_map |= 1 << idx;
296 /* Now call PreLoad on all the vertex buffers. In the very rare case
297 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
298 * The vertex buffer can now use the strided structure in the device instead of finding its
299 * own again.
301 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
302 * once in there. */
303 for (i = 0; i < stream_count; ++i)
305 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
306 if (vb) IWineD3DBuffer_PreLoad(vb);
310 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
311 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
313 e->d3d_type = strided->dwType;
314 e->size = WINED3D_ATR_SIZE(strided->dwType);
315 e->format = WINED3D_ATR_FORMAT(strided->dwType);
316 e->type = WINED3D_ATR_GLTYPE(strided->dwType);
317 e->stride = strided->dwStride;
318 e->normalized = WINED3D_ATR_NORMALIZED(strided->dwType);
319 e->data = strided->lpData;
320 e->type_size = WINED3D_ATR_TYPESIZE(strided->dwType);
321 e->stream_idx = 0;
322 e->buffer_object = 0;
325 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
326 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
328 unsigned int i;
330 memset(stream_info, 0, sizeof(*stream_info));
332 if (strided->position.lpData)
333 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
334 if (strided->normal.lpData)
335 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
336 if (strided->diffuse.lpData)
337 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
338 if (strided->specular.lpData)
339 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
341 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
343 if (strided->texCoords[i].lpData)
344 stream_info_element_from_strided(This, &strided->texCoords[i],
345 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
348 stream_info->position_transformed = strided->position_transformed;
350 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
352 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].d3d_type == WINED3DDECLTYPE_D3DCOLOR)
354 stream_info->swizzle_map |= 1 << i;
356 stream_info->use_map |= 1 << i;
360 /**********************************************************
361 * IUnknown parts follows
362 **********************************************************/
364 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
368 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
369 if (IsEqualGUID(riid, &IID_IUnknown)
370 || IsEqualGUID(riid, &IID_IWineD3DBase)
371 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
372 IUnknown_AddRef(iface);
373 *ppobj = This;
374 return S_OK;
376 *ppobj = NULL;
377 return E_NOINTERFACE;
380 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
382 ULONG refCount = InterlockedIncrement(&This->ref);
384 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
385 return refCount;
388 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
390 ULONG refCount = InterlockedDecrement(&This->ref);
392 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
394 if (!refCount) {
395 UINT i;
397 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
398 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
399 This->multistate_funcs[i] = NULL;
402 /* TODO: Clean up all the surfaces and textures! */
403 /* NOTE: You must release the parent if the object was created via a callback
404 ** ***************************/
406 if (!list_empty(&This->resources)) {
407 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
408 dumpResources(&This->resources);
411 if(This->contexts) ERR("Context array not freed!\n");
412 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
413 This->haveHardwareCursor = FALSE;
415 IWineD3D_Release(This->wineD3D);
416 This->wineD3D = NULL;
417 HeapFree(GetProcessHeap(), 0, This);
418 TRACE("Freed device %p\n", This);
419 This = NULL;
421 return refCount;
424 /**********************************************************
425 * IWineD3DDevice implementation follows
426 **********************************************************/
427 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
429 *pParent = This->parent;
430 IUnknown_AddRef(This->parent);
431 return WINED3D_OK;
434 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
435 struct wined3d_buffer_desc *desc, IUnknown *parent, IWineD3DBuffer **buffer)
437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
438 struct wined3d_buffer *object;
439 HRESULT hr;
441 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
444 if (!object)
446 ERR("Failed to allocate memory\n");
447 return E_OUTOFMEMORY;
450 object->vtbl = &wined3d_buffer_vtbl;
451 object->desc = *desc;
453 FIXME("Ignoring access flags (pool)\n");
455 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
456 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
457 if (FAILED(hr))
459 WARN("Failed to initialize resource, returning %#x\n", hr);
460 HeapFree(GetProcessHeap(), 0, object);
461 return hr;
464 TRACE("Created resource %p\n", object);
466 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
468 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
469 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
471 *buffer = (IWineD3DBuffer *)object;
473 return WINED3D_OK;
476 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
477 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
480 /* Dummy format for now */
481 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
482 struct wined3d_buffer *object;
483 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
484 HRESULT hr;
485 BOOL conv;
487 if(Size == 0) {
488 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
489 *ppVertexBuffer = NULL;
490 return WINED3DERR_INVALIDCALL;
491 } else if(Pool == WINED3DPOOL_SCRATCH) {
492 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
493 * anyway, SCRATCH vertex buffers aren't usable anywhere
495 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
496 *ppVertexBuffer = NULL;
497 return WINED3DERR_INVALIDCALL;
500 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
501 if (!object)
503 ERR("Out of memory\n");
504 *ppVertexBuffer = NULL;
505 return WINED3DERR_OUTOFVIDEOMEMORY;
508 object->vtbl = &wined3d_buffer_vtbl;
509 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, format_desc, Pool, parent);
510 if (FAILED(hr))
512 WARN("Failed to initialize resource, returning %#x\n", hr);
513 HeapFree(GetProcessHeap(), 0, object);
514 *ppVertexBuffer = NULL;
515 return hr;
518 TRACE("(%p) : Created resource %p\n", This, object);
520 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
522 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);
523 *ppVertexBuffer = (IWineD3DBuffer *)object;
525 object->fvf = FVF;
527 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
528 * drawStridedFast (half-life 2).
530 * Basically converting the vertices in the buffer is quite expensive, and observations
531 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
532 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
534 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
535 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
536 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
537 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
538 * dx7 apps.
539 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
540 * more. In this call we can convert dx7 buffers too.
542 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
543 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
544 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
545 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
546 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
547 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
548 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
549 } else if(dxVersion <= 7 && conv) {
550 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
551 } else {
552 object->flags |= WINED3D_BUFFER_CREATEBO;
554 return WINED3D_OK;
557 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
558 GLenum error, glUsage;
559 TRACE("Creating VBO for Index Buffer %p\n", object);
561 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
562 * restored on the next draw
564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
566 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
567 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
568 ENTER_GL();
570 while(glGetError());
572 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
573 error = glGetError();
574 if(error != GL_NO_ERROR || object->vbo == 0) {
575 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
576 goto out;
579 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
580 error = glGetError();
581 if(error != GL_NO_ERROR) {
582 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
583 goto out;
586 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
587 * copy no readback will be needed
589 glUsage = GL_STATIC_DRAW_ARB;
590 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
591 error = glGetError();
592 if(error != GL_NO_ERROR) {
593 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
594 goto out;
596 LEAVE_GL();
597 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
598 return;
600 out:
601 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
602 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
603 LEAVE_GL();
604 object->vbo = 0;
607 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
608 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
609 HANDLE *sharedHandle, IUnknown *parent) {
610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
611 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
612 IWineD3DIndexBufferImpl *object;
613 HRESULT hr;
615 TRACE("(%p) Creating index buffer\n", This);
617 /* Allocate the storage for the device */
618 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
619 if (!object)
621 ERR("Out of memory\n");
622 *ppIndexBuffer = NULL;
623 return WINED3DERR_OUTOFVIDEOMEMORY;
626 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
627 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, format_desc, Pool, parent);
628 if (FAILED(hr))
630 WARN("Failed to initialize resource, returning %#x\n", hr);
631 HeapFree(GetProcessHeap(), 0, object);
632 *ppIndexBuffer = NULL;
633 return hr;
636 TRACE("(%p) : Created resource %p\n", This, object);
638 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
640 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
641 CreateIndexBufferVBO(This, object);
644 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
645 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
646 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
648 return WINED3D_OK;
651 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
654 IWineD3DStateBlockImpl *object;
655 unsigned int i, j;
656 HRESULT temp_result;
658 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
659 if(!object)
661 ERR("Out of memory\n");
662 *ppStateBlock = NULL;
663 return WINED3DERR_OUTOFVIDEOMEMORY;
666 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
667 object->wineD3DDevice = This;
668 object->parent = parent;
669 object->ref = 1;
670 object->blockType = Type;
672 *ppStateBlock = (IWineD3DStateBlock *)object;
674 for(i = 0; i < LIGHTMAP_SIZE; i++) {
675 list_init(&object->lightMap[i]);
678 temp_result = allocate_shader_constants(object);
679 if (FAILED(temp_result))
681 HeapFree(GetProcessHeap(), 0, object);
682 return temp_result;
685 /* Special case - Used during initialization to produce a placeholder stateblock
686 so other functions called can update a state block */
687 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
689 /* Don't bother increasing the reference count otherwise a device will never
690 be freed due to circular dependencies */
691 return WINED3D_OK;
694 /* Otherwise, might as well set the whole state block to the appropriate values */
695 if (This->stateBlock != NULL)
696 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
697 else
698 memset(object->streamFreq, 1, sizeof(object->streamFreq));
700 /* Reset the ref and type after kludging it */
701 object->wineD3DDevice = This;
702 object->ref = 1;
703 object->blockType = Type;
705 TRACE("Updating changed flags appropriate for type %d\n", Type);
707 if (Type == WINED3DSBT_ALL) {
709 TRACE("ALL => Pretend everything has changed\n");
710 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
712 /* Lights are not part of the changed / set structure */
713 for(j = 0; j < LIGHTMAP_SIZE; j++) {
714 struct list *e;
715 LIST_FOR_EACH(e, &object->lightMap[j]) {
716 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
717 light->changed = TRUE;
718 light->enabledChanged = TRUE;
721 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
722 object->contained_render_states[j - 1] = j;
724 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
725 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
726 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
727 object->contained_transform_states[j - 1] = j;
729 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
730 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
731 object->contained_vs_consts_f[j] = j;
733 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
734 for(j = 0; j < MAX_CONST_I; j++) {
735 object->contained_vs_consts_i[j] = j;
737 object->num_contained_vs_consts_i = MAX_CONST_I;
738 for(j = 0; j < MAX_CONST_B; j++) {
739 object->contained_vs_consts_b[j] = j;
741 object->num_contained_vs_consts_b = MAX_CONST_B;
742 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
743 object->contained_ps_consts_f[j] = j;
745 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
746 for(j = 0; j < MAX_CONST_I; j++) {
747 object->contained_ps_consts_i[j] = j;
749 object->num_contained_ps_consts_i = MAX_CONST_I;
750 for(j = 0; j < MAX_CONST_B; j++) {
751 object->contained_ps_consts_b[j] = j;
753 object->num_contained_ps_consts_b = MAX_CONST_B;
754 for(i = 0; i < MAX_TEXTURES; i++) {
755 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
757 object->contained_tss_states[object->num_contained_tss_states].stage = i;
758 object->contained_tss_states[object->num_contained_tss_states].state = j;
759 object->num_contained_tss_states++;
762 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
763 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
764 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
765 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
766 object->num_contained_sampler_states++;
770 for(i = 0; i < MAX_STREAMS; i++) {
771 if(object->streamSource[i]) {
772 IWineD3DBuffer_AddRef(object->streamSource[i]);
775 if(object->pIndexData) {
776 IWineD3DIndexBuffer_AddRef(object->pIndexData);
778 if(object->vertexShader) {
779 IWineD3DVertexShader_AddRef(object->vertexShader);
781 if(object->pixelShader) {
782 IWineD3DPixelShader_AddRef(object->pixelShader);
785 } else if (Type == WINED3DSBT_PIXELSTATE) {
787 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
788 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
790 object->changed.pixelShader = TRUE;
792 /* Pixel Shader Constants */
793 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
794 object->contained_ps_consts_f[i] = i;
795 object->changed.pixelShaderConstantsF[i] = TRUE;
797 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
798 for (i = 0; i < MAX_CONST_B; ++i) {
799 object->contained_ps_consts_b[i] = i;
800 object->changed.pixelShaderConstantsB |= (1 << i);
802 object->num_contained_ps_consts_b = MAX_CONST_B;
803 for (i = 0; i < MAX_CONST_I; ++i) {
804 object->contained_ps_consts_i[i] = i;
805 object->changed.pixelShaderConstantsI |= (1 << i);
807 object->num_contained_ps_consts_i = MAX_CONST_I;
809 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
810 DWORD rs = SavedPixelStates_R[i];
811 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
812 object->contained_render_states[i] = rs;
814 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
815 for (j = 0; j < MAX_TEXTURES; j++) {
816 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
817 DWORD state = SavedPixelStates_T[i];
818 object->changed.textureState[j] |= 1 << state;
819 object->contained_tss_states[object->num_contained_tss_states].stage = j;
820 object->contained_tss_states[object->num_contained_tss_states].state = state;
821 object->num_contained_tss_states++;
824 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
825 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
826 DWORD state = SavedPixelStates_S[i];
827 object->changed.samplerState[j] |= 1 << state;
828 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
829 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
830 object->num_contained_sampler_states++;
833 if(object->pixelShader) {
834 IWineD3DPixelShader_AddRef(object->pixelShader);
837 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
838 * on them. This makes releasing the buffer easier
840 for(i = 0; i < MAX_STREAMS; i++) {
841 object->streamSource[i] = NULL;
843 object->pIndexData = NULL;
844 object->vertexShader = NULL;
846 } else if (Type == WINED3DSBT_VERTEXSTATE) {
848 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
849 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
851 object->changed.vertexShader = TRUE;
853 /* Vertex Shader Constants */
854 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
855 object->changed.vertexShaderConstantsF[i] = TRUE;
856 object->contained_vs_consts_f[i] = i;
858 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
859 for (i = 0; i < MAX_CONST_B; ++i) {
860 object->contained_vs_consts_b[i] = i;
861 object->changed.vertexShaderConstantsB |= (1 << i);
863 object->num_contained_vs_consts_b = MAX_CONST_B;
864 for (i = 0; i < MAX_CONST_I; ++i) {
865 object->contained_vs_consts_i[i] = i;
866 object->changed.vertexShaderConstantsI |= (1 << i);
868 object->num_contained_vs_consts_i = MAX_CONST_I;
869 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
870 DWORD rs = SavedVertexStates_R[i];
871 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
872 object->contained_render_states[i] = rs;
874 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
875 for (j = 0; j < MAX_TEXTURES; j++) {
876 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
877 DWORD state = SavedVertexStates_T[i];
878 object->changed.textureState[j] |= 1 << state;
879 object->contained_tss_states[object->num_contained_tss_states].stage = j;
880 object->contained_tss_states[object->num_contained_tss_states].state = state;
881 object->num_contained_tss_states++;
884 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
885 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
886 DWORD state = SavedVertexStates_S[i];
887 object->changed.samplerState[j] |= 1 << state;
888 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
889 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
890 object->num_contained_sampler_states++;
894 for(j = 0; j < LIGHTMAP_SIZE; j++) {
895 struct list *e;
896 LIST_FOR_EACH(e, &object->lightMap[j]) {
897 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
898 light->changed = TRUE;
899 light->enabledChanged = TRUE;
903 for(i = 0; i < MAX_STREAMS; i++) {
904 if(object->streamSource[i]) {
905 IWineD3DBuffer_AddRef(object->streamSource[i]);
908 if(object->vertexShader) {
909 IWineD3DVertexShader_AddRef(object->vertexShader);
911 object->pIndexData = NULL;
912 object->pixelShader = NULL;
913 } else {
914 FIXME("Unrecognized state block type %d\n", Type);
917 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
918 return WINED3D_OK;
921 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) {
922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
923 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
924 unsigned int Size = 1;
925 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
926 UINT mul_4w, mul_4h;
927 HRESULT hr;
929 TRACE("(%p) Create surface\n",This);
931 if(MultisampleQuality > 0) {
932 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
933 MultisampleQuality=0;
936 /** FIXME: Check that the format is supported
937 * by the device.
938 *******************************/
940 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
941 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
942 * space!
943 *********************************/
944 mul_4w = (Width + 3) & ~3;
945 mul_4h = (Height + 3) & ~3;
946 if (WINED3DFMT_UNKNOWN == Format) {
947 Size = 0;
948 } else if (Format == WINED3DFMT_DXT1) {
949 /* DXT1 is half byte per pixel */
950 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
952 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
953 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
954 Format == WINED3DFMT_ATI2N) {
955 Size = (mul_4w * glDesc->byte_count * mul_4h);
956 } else {
957 /* The pitch is a multiple of 4 bytes */
958 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
959 Size *= Height;
962 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
964 /** Create and initialise the surface resource **/
965 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
966 if (!object)
968 ERR("Out of memory\n");
969 *ppSurface = NULL;
970 return WINED3DERR_OUTOFVIDEOMEMORY;
973 /* Look at the implementation and set the correct Vtable */
974 switch(Impl)
976 case SURFACE_OPENGL:
977 /* Check if a 3D adapter is available when creating gl surfaces */
978 if (!This->adapter)
980 ERR("OpenGL surfaces are not available without opengl\n");
981 HeapFree(GetProcessHeap(), 0, object);
982 return WINED3DERR_NOTAVAILABLE;
984 object->lpVtbl = &IWineD3DSurface_Vtbl;
985 break;
987 case SURFACE_GDI:
988 object->lpVtbl = &IWineGDISurface_Vtbl;
989 break;
991 default:
992 /* To be sure to catch this */
993 ERR("Unknown requested surface implementation %d!\n", Impl);
994 HeapFree(GetProcessHeap(), 0, object);
995 return WINED3DERR_INVALIDCALL;
998 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
999 if (FAILED(hr))
1001 WARN("Failed to initialize resource, returning %#x\n", hr);
1002 HeapFree(GetProcessHeap(), 0, object);
1003 *ppSurface = NULL;
1004 return hr;
1007 TRACE("(%p) : Created resource %p\n", This, object);
1009 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1011 *ppSurface = (IWineD3DSurface *)object;
1013 /* "Standalone" surface */
1014 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1016 object->currentDesc.Width = Width;
1017 object->currentDesc.Height = Height;
1018 object->currentDesc.MultiSampleType = MultiSample;
1019 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1020 object->glDescription.level = Level;
1021 list_init(&object->overlays);
1023 /* Flags */
1024 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1025 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1026 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1027 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1029 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1031 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1032 * this function is too deep to need to care about things like this.
1033 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1034 * ****************************************/
1035 switch(Pool) {
1036 case WINED3DPOOL_SCRATCH:
1037 if(!Lockable)
1038 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1039 "which are mutually exclusive, setting lockable to TRUE\n");
1040 Lockable = TRUE;
1041 break;
1042 case WINED3DPOOL_SYSTEMMEM:
1043 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1044 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1045 case WINED3DPOOL_MANAGED:
1046 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1047 "Usage of DYNAMIC which are mutually exclusive, not doing "
1048 "anything just telling you.\n");
1049 break;
1050 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1051 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1052 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1053 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1054 break;
1055 default:
1056 FIXME("(%p) Unknown pool %d\n", This, Pool);
1057 break;
1060 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1061 FIXME("Trying to create a render target that isn't in the default pool\n");
1064 /* mark the texture as dirty so that it gets loaded first time around*/
1065 surface_add_dirty_rect(*ppSurface, NULL);
1066 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1067 This, Width, Height, Format, debug_d3dformat(Format),
1068 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1070 list_init(&object->renderbuffers);
1072 /* Call the private setup routine */
1073 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1074 if (FAILED(hr))
1076 ERR("Private setup failed, returning %#x\n", hr);
1077 IWineD3DSurface_Release(*ppSurface);
1078 *ppSurface = NULL;
1079 return hr;
1082 return hr;
1085 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1086 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1088 struct wined3d_rendertarget_view *object;
1090 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1091 if (!object)
1093 ERR("Failed to allocate memory\n");
1094 return E_OUTOFMEMORY;
1097 object->vtbl = &wined3d_rendertarget_view_vtbl;
1098 object->refcount = 1;
1099 IWineD3DResource_AddRef(resource);
1100 object->resource = resource;
1101 object->parent = parent;
1103 *rendertarget_view = (IWineD3DRendertargetView *)object;
1105 return WINED3D_OK;
1108 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1109 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1110 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
1112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1113 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1114 IWineD3DTextureImpl *object;
1115 unsigned int i;
1116 UINT tmpW;
1117 UINT tmpH;
1118 HRESULT hr;
1119 unsigned int pow2Width;
1120 unsigned int pow2Height;
1122 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1123 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1124 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1126 /* TODO: It should only be possible to create textures for formats
1127 that are reported as supported */
1128 if (WINED3DFMT_UNKNOWN >= Format) {
1129 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1130 return WINED3DERR_INVALIDCALL;
1133 /* Non-power2 support */
1134 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1136 pow2Width = Width;
1137 pow2Height = Height;
1139 else
1141 /* Find the nearest pow2 match */
1142 pow2Width = pow2Height = 1;
1143 while (pow2Width < Width) pow2Width <<= 1;
1144 while (pow2Height < Height) pow2Height <<= 1;
1146 if (pow2Width != Width || pow2Height != Height)
1148 if (Levels > 1)
1150 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1151 return WINED3DERR_INVALIDCALL;
1153 Levels = 1;
1157 /* Calculate levels for mip mapping */
1158 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1160 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1162 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1163 return WINED3DERR_INVALIDCALL;
1166 if (Levels > 1)
1168 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1169 return WINED3DERR_INVALIDCALL;
1172 Levels = 1;
1174 else if (!Levels)
1176 Levels = wined3d_log2i(max(Width, Height)) + 1;
1177 TRACE("Calculated levels = %d\n", Levels);
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1181 if (!object)
1183 ERR("Out of memory\n");
1184 *ppTexture = NULL;
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 object->lpVtbl = &IWineD3DTexture_Vtbl;
1189 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1190 if (FAILED(hr))
1192 WARN("Failed to initialize resource, returning %#x\n", hr);
1193 HeapFree(GetProcessHeap(), 0, object);
1194 *ppTexture = NULL;
1195 return hr;
1198 TRACE("(%p) : Created resource %p\n", This, object);
1200 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1202 *ppTexture = (IWineD3DTexture *)object;
1204 basetexture_init(&object->baseTexture, Levels, Usage);
1206 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1208 object->baseTexture.minMipLookup = minMipLookup;
1209 object->baseTexture.magLookup = magLookup;
1210 } else {
1211 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1212 object->baseTexture.magLookup = magLookup_noFilter;
1215 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1216 /* Precalculated scaling for 'faked' non power of two texture coords.
1217 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1218 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1219 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1221 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1222 object->baseTexture.pow2Matrix[0] = 1.0;
1223 object->baseTexture.pow2Matrix[5] = 1.0;
1224 object->baseTexture.pow2Matrix[10] = 1.0;
1225 object->baseTexture.pow2Matrix[15] = 1.0;
1226 object->target = GL_TEXTURE_2D;
1227 object->cond_np2 = TRUE;
1228 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1229 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1230 (Width != pow2Width || Height != pow2Height) &&
1231 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1233 object->baseTexture.pow2Matrix[0] = (float)Width;
1234 object->baseTexture.pow2Matrix[5] = (float)Height;
1235 object->baseTexture.pow2Matrix[10] = 1.0;
1236 object->baseTexture.pow2Matrix[15] = 1.0;
1237 object->target = GL_TEXTURE_RECTANGLE_ARB;
1238 object->cond_np2 = TRUE;
1239 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1240 } else {
1241 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1242 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1243 object->baseTexture.pow2Matrix[10] = 1.0;
1244 object->baseTexture.pow2Matrix[15] = 1.0;
1245 object->target = GL_TEXTURE_2D;
1246 object->cond_np2 = FALSE;
1248 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1250 /* Generate all the surfaces */
1251 tmpW = Width;
1252 tmpH = Height;
1253 for (i = 0; i < object->baseTexture.levels; i++)
1255 /* use the callback to create the texture surface */
1256 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1257 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1258 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1259 FIXME("Failed to create surface %p\n", object);
1260 /* clean up */
1261 object->surfaces[i] = NULL;
1262 IWineD3DTexture_Release((IWineD3DTexture *)object);
1264 *ppTexture = NULL;
1265 return hr;
1268 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1269 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1270 surface_set_texture_target(object->surfaces[i], object->target);
1271 /* calculate the next mipmap level */
1272 tmpW = max(1, tmpW >> 1);
1273 tmpH = max(1, tmpH >> 1);
1275 object->baseTexture.internal_preload = texture_internal_preload;
1277 TRACE("(%p) : Created texture %p\n", This, object);
1278 return WINED3D_OK;
1281 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1282 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1283 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1286 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1287 IWineD3DVolumeTextureImpl *object;
1288 unsigned int i;
1289 UINT tmpW;
1290 UINT tmpH;
1291 UINT tmpD;
1292 HRESULT hr;
1294 /* TODO: It should only be possible to create textures for formats
1295 that are reported as supported */
1296 if (WINED3DFMT_UNKNOWN >= Format) {
1297 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1298 return WINED3DERR_INVALIDCALL;
1300 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1301 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1302 return WINED3DERR_INVALIDCALL;
1305 /* Calculate levels for mip mapping */
1306 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1308 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1310 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1311 return WINED3DERR_INVALIDCALL;
1314 if (Levels > 1)
1316 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1317 return WINED3DERR_INVALIDCALL;
1320 Levels = 1;
1322 else if (!Levels)
1324 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1325 TRACE("Calculated levels = %d\n", Levels);
1328 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1329 if (!object)
1331 ERR("Out of memory\n");
1332 *ppVolumeTexture = NULL;
1333 return WINED3DERR_OUTOFVIDEOMEMORY;
1336 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1337 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1338 if (FAILED(hr))
1340 WARN("Failed to initialize resource, returning %#x\n", hr);
1341 HeapFree(GetProcessHeap(), 0, object);
1342 *ppVolumeTexture = NULL;
1343 return hr;
1346 TRACE("(%p) : Created resource %p\n", This, object);
1348 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1350 basetexture_init(&object->baseTexture, Levels, Usage);
1352 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1353 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1355 /* Is NP2 support for volumes needed? */
1356 object->baseTexture.pow2Matrix[ 0] = 1.0;
1357 object->baseTexture.pow2Matrix[ 5] = 1.0;
1358 object->baseTexture.pow2Matrix[10] = 1.0;
1359 object->baseTexture.pow2Matrix[15] = 1.0;
1361 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1363 object->baseTexture.minMipLookup = minMipLookup;
1364 object->baseTexture.magLookup = magLookup;
1365 } else {
1366 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1367 object->baseTexture.magLookup = magLookup_noFilter;
1370 /* Generate all the surfaces */
1371 tmpW = Width;
1372 tmpH = Height;
1373 tmpD = Depth;
1375 for (i = 0; i < object->baseTexture.levels; i++)
1377 HRESULT hr;
1378 /* Create the volume */
1379 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1380 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1381 if(FAILED(hr)) {
1382 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1383 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1384 *ppVolumeTexture = NULL;
1385 return hr;
1388 /* Set its container to this object */
1389 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1391 /* calculate the next mipmap level */
1392 tmpW = max(1, tmpW >> 1);
1393 tmpH = max(1, tmpH >> 1);
1394 tmpD = max(1, tmpD >> 1);
1396 object->baseTexture.internal_preload = volumetexture_internal_preload;
1398 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1399 TRACE("(%p) : Created volume texture %p\n", This, object);
1400 return WINED3D_OK;
1403 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1404 UINT Width, UINT Height, UINT Depth,
1405 DWORD Usage,
1406 WINED3DFORMAT Format, WINED3DPOOL Pool,
1407 IWineD3DVolume** ppVolume,
1408 HANDLE* pSharedHandle, IUnknown *parent) {
1410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1411 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1412 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1413 HRESULT hr;
1415 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1416 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1417 return WINED3DERR_INVALIDCALL;
1420 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1421 if (!object)
1423 ERR("Out of memory\n");
1424 *ppVolume = NULL;
1425 return WINED3DERR_OUTOFVIDEOMEMORY;
1428 object->lpVtbl = &IWineD3DVolume_Vtbl;
1429 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1430 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1431 if (FAILED(hr))
1433 WARN("Failed to initialize resource, returning %#x\n", hr);
1434 HeapFree(GetProcessHeap(), 0, object);
1435 *ppVolume = NULL;
1436 return hr;
1439 TRACE("(%p) : Created resource %p\n", This, object);
1441 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1443 *ppVolume = (IWineD3DVolume *)object;
1445 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1446 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1448 object->currentDesc.Width = Width;
1449 object->currentDesc.Height = Height;
1450 object->currentDesc.Depth = Depth;
1452 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1453 object->lockable = TRUE;
1454 object->locked = FALSE;
1455 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1456 object->dirty = TRUE;
1458 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1460 return WINED3D_OK;
1463 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1464 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1465 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1468 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1469 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1470 unsigned int i, j;
1471 UINT tmpW;
1472 HRESULT hr;
1473 unsigned int pow2EdgeLength;
1475 /* TODO: It should only be possible to create textures for formats
1476 that are reported as supported */
1477 if (WINED3DFMT_UNKNOWN >= Format) {
1478 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1479 return WINED3DERR_INVALIDCALL;
1482 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1483 WARN("(%p) : Tried to create not supported cube texture\n", This);
1484 return WINED3DERR_INVALIDCALL;
1487 /* Calculate levels for mip mapping */
1488 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1490 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1492 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1493 return WINED3DERR_INVALIDCALL;
1496 if (Levels > 1)
1498 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1499 return WINED3DERR_INVALIDCALL;
1502 Levels = 1;
1504 else if (!Levels)
1506 Levels = wined3d_log2i(EdgeLength) + 1;
1507 TRACE("Calculated levels = %d\n", Levels);
1510 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1511 if (!object)
1513 ERR("Out of memory\n");
1514 *ppCubeTexture = NULL;
1515 return WINED3DERR_OUTOFVIDEOMEMORY;
1518 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1519 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1520 if (FAILED(hr))
1522 WARN("Failed to initialize resource, returning %#x\n", hr);
1523 HeapFree(GetProcessHeap(), 0, object);
1524 *ppCubeTexture = NULL;
1525 return hr;
1528 TRACE("(%p) : Created resource %p\n", This, object);
1530 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1532 basetexture_init(&object->baseTexture, Levels, Usage);
1534 TRACE("(%p) Create Cube Texture\n", This);
1536 /* Find the nearest pow2 match */
1537 pow2EdgeLength = 1;
1538 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1540 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1541 /* Precalculated scaling for 'faked' non power of two texture coords */
1542 object->baseTexture.pow2Matrix[ 0] = 1.0;
1543 object->baseTexture.pow2Matrix[ 5] = 1.0;
1544 object->baseTexture.pow2Matrix[10] = 1.0;
1545 object->baseTexture.pow2Matrix[15] = 1.0;
1546 } else {
1547 /* Precalculated scaling for 'faked' non power of two texture coords */
1548 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1549 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1550 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1551 object->baseTexture.pow2Matrix[15] = 1.0;
1554 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1556 object->baseTexture.minMipLookup = minMipLookup;
1557 object->baseTexture.magLookup = magLookup;
1558 } else {
1559 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1560 object->baseTexture.magLookup = magLookup_noFilter;
1563 /* Generate all the surfaces */
1564 tmpW = EdgeLength;
1565 for (i = 0; i < object->baseTexture.levels; i++) {
1567 /* Create the 6 faces */
1568 for (j = 0; j < 6; j++) {
1569 static const GLenum cube_targets[6] = {
1570 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1571 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1572 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1573 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1574 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1575 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1578 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1579 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1580 if (FAILED(hr))
1582 FIXME("(%p) Failed to create surface\n",object);
1583 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1584 *ppCubeTexture = NULL;
1585 return hr;
1587 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1588 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1589 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1591 tmpW = max(1, tmpW >> 1);
1593 object->baseTexture.internal_preload = cubetexture_internal_preload;
1595 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1596 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1597 return WINED3D_OK;
1600 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1602 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1603 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1604 const IWineD3DQueryVtbl *vtable;
1606 /* Just a check to see if we support this type of query */
1607 switch(Type) {
1608 case WINED3DQUERYTYPE_OCCLUSION:
1609 TRACE("(%p) occlusion query\n", This);
1610 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1611 hr = WINED3D_OK;
1612 else
1613 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1615 vtable = &IWineD3DOcclusionQuery_Vtbl;
1616 break;
1618 case WINED3DQUERYTYPE_EVENT:
1619 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1620 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1621 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1623 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1625 vtable = &IWineD3DEventQuery_Vtbl;
1626 hr = WINED3D_OK;
1627 break;
1629 case WINED3DQUERYTYPE_VCACHE:
1630 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1631 case WINED3DQUERYTYPE_VERTEXSTATS:
1632 case WINED3DQUERYTYPE_TIMESTAMP:
1633 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1634 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1635 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1636 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1637 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1638 case WINED3DQUERYTYPE_PIXELTIMINGS:
1639 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1640 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1641 default:
1642 /* Use the base Query vtable until we have a special one for each query */
1643 vtable = &IWineD3DQuery_Vtbl;
1644 FIXME("(%p) Unhandled query type %d\n", This, Type);
1646 if(NULL == ppQuery || hr != WINED3D_OK) {
1647 return hr;
1650 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1651 if(!object)
1653 ERR("Out of memory\n");
1654 *ppQuery = NULL;
1655 return WINED3DERR_OUTOFVIDEOMEMORY;
1658 object->lpVtbl = vtable;
1659 object->type = Type;
1660 object->state = QUERY_CREATED;
1661 object->wineD3DDevice = This;
1662 object->parent = parent;
1663 object->ref = 1;
1665 *ppQuery = (IWineD3DQuery *)object;
1667 /* allocated the 'extended' data based on the type of query requested */
1668 switch(Type){
1669 case WINED3DQUERYTYPE_OCCLUSION:
1670 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1671 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1673 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1674 TRACE("(%p) Allocating data for an occlusion query\n", This);
1676 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1677 ENTER_GL();
1678 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1679 LEAVE_GL();
1680 break;
1682 case WINED3DQUERYTYPE_EVENT:
1683 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1684 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1686 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1687 ENTER_GL();
1688 if(GL_SUPPORT(APPLE_FENCE)) {
1689 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1690 checkGLcall("glGenFencesAPPLE");
1691 } else if(GL_SUPPORT(NV_FENCE)) {
1692 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1693 checkGLcall("glGenFencesNV");
1695 LEAVE_GL();
1696 break;
1698 case WINED3DQUERYTYPE_VCACHE:
1699 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1700 case WINED3DQUERYTYPE_VERTEXSTATS:
1701 case WINED3DQUERYTYPE_TIMESTAMP:
1702 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1703 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1704 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1705 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1706 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1707 case WINED3DQUERYTYPE_PIXELTIMINGS:
1708 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1709 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1710 default:
1711 object->extendedData = 0;
1712 FIXME("(%p) Unhandled query type %d\n",This , Type);
1714 TRACE("(%p) : Created Query %p\n", This, object);
1715 return WINED3D_OK;
1718 /*****************************************************************************
1719 * IWineD3DDeviceImpl_SetupFullscreenWindow
1721 * Helper function that modifies a HWND's Style and ExStyle for proper
1722 * fullscreen use.
1724 * Params:
1725 * iface: Pointer to the IWineD3DDevice interface
1726 * window: Window to setup
1728 *****************************************************************************/
1729 static LONG fullscreen_style(LONG orig_style) {
1730 LONG style = orig_style;
1731 style &= ~WS_CAPTION;
1732 style &= ~WS_THICKFRAME;
1734 /* Make sure the window is managed, otherwise we won't get keyboard input */
1735 style |= WS_POPUP | WS_SYSMENU;
1737 return style;
1740 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1741 LONG exStyle = orig_exStyle;
1743 /* Filter out window decorations */
1744 exStyle &= ~WS_EX_WINDOWEDGE;
1745 exStyle &= ~WS_EX_CLIENTEDGE;
1747 return exStyle;
1750 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1753 LONG style, exStyle;
1754 /* Don't do anything if an original style is stored.
1755 * That shouldn't happen
1757 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1758 if (This->style || This->exStyle) {
1759 ERR("(%p): Want to change the window parameters of HWND %p, but "
1760 "another style is stored for restoration afterwards\n", This, window);
1763 /* Get the parameters and save them */
1764 style = GetWindowLongW(window, GWL_STYLE);
1765 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1766 This->style = style;
1767 This->exStyle = exStyle;
1769 style = fullscreen_style(style);
1770 exStyle = fullscreen_exStyle(exStyle);
1772 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1773 This->style, This->exStyle, style, exStyle);
1775 SetWindowLongW(window, GWL_STYLE, style);
1776 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1778 /* Inform the window about the update. */
1779 SetWindowPos(window, HWND_TOP, 0, 0,
1780 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1783 /*****************************************************************************
1784 * IWineD3DDeviceImpl_RestoreWindow
1786 * Helper function that restores a windows' properties when taking it out
1787 * of fullscreen mode
1789 * Params:
1790 * iface: Pointer to the IWineD3DDevice interface
1791 * window: Window to setup
1793 *****************************************************************************/
1794 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1796 LONG style, exStyle;
1798 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1799 * switch, do nothing
1801 if (!This->style && !This->exStyle) return;
1803 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1804 This, window, This->style, This->exStyle);
1806 style = GetWindowLongW(window, GWL_STYLE);
1807 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1809 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1810 * Some applications change it before calling Reset() when switching between windowed and
1811 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1813 if(style == fullscreen_style(This->style) &&
1814 exStyle == fullscreen_style(This->exStyle)) {
1815 SetWindowLongW(window, GWL_STYLE, This->style);
1816 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1819 /* Delete the old values */
1820 This->style = 0;
1821 This->exStyle = 0;
1823 /* Inform the window about the update */
1824 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1825 0, 0, 0, 0, /* Pos, Size, ignored */
1826 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1829 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1830 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1831 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1832 IUnknown *parent, WINED3DSURFTYPE surface_type)
1834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1836 HDC hDc;
1837 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1838 HRESULT hr;
1839 IUnknown *bufferParent;
1840 BOOL displaymode_set = FALSE;
1841 WINED3DDISPLAYMODE Mode;
1842 const struct GlPixelFormatDesc *format_desc;
1844 TRACE("(%p) : Created Additional Swap Chain\n", This);
1846 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1847 * does a device hold a reference to a swap chain giving them a lifetime of the device
1848 * or does the swap chain notify the device of its destruction.
1849 *******************************/
1851 /* Check the params */
1852 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1853 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1854 return WINED3DERR_INVALIDCALL;
1855 } else if (pPresentationParameters->BackBufferCount > 1) {
1856 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");
1859 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1860 if(!object)
1862 ERR("Out of memory\n");
1863 *ppSwapChain = NULL;
1864 return WINED3DERR_OUTOFVIDEOMEMORY;
1867 switch(surface_type) {
1868 case SURFACE_GDI:
1869 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1870 break;
1871 case SURFACE_OPENGL:
1872 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1873 break;
1874 case SURFACE_UNKNOWN:
1875 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1876 HeapFree(GetProcessHeap(), 0, object);
1877 return WINED3DERR_INVALIDCALL;
1879 object->wineD3DDevice = This;
1880 object->parent = parent;
1881 object->ref = 1;
1883 *ppSwapChain = (IWineD3DSwapChain *)object;
1885 /*********************
1886 * Lookup the window Handle and the relating X window handle
1887 ********************/
1889 /* Setup hwnd we are using, plus which display this equates to */
1890 object->win_handle = pPresentationParameters->hDeviceWindow;
1891 if (!object->win_handle) {
1892 object->win_handle = This->createParms.hFocusWindow;
1894 if(!pPresentationParameters->Windowed && object->win_handle) {
1895 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1896 pPresentationParameters->BackBufferWidth,
1897 pPresentationParameters->BackBufferHeight);
1900 hDc = GetDC(object->win_handle);
1901 TRACE("Using hDc %p\n", hDc);
1903 if (NULL == hDc) {
1904 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1905 return WINED3DERR_NOTAVAILABLE;
1908 /* Get info on the current display setup */
1909 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1910 object->orig_width = Mode.Width;
1911 object->orig_height = Mode.Height;
1912 object->orig_fmt = Mode.Format;
1913 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1915 if (pPresentationParameters->Windowed &&
1916 ((pPresentationParameters->BackBufferWidth == 0) ||
1917 (pPresentationParameters->BackBufferHeight == 0) ||
1918 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1920 RECT Rect;
1921 GetClientRect(object->win_handle, &Rect);
1923 if (pPresentationParameters->BackBufferWidth == 0) {
1924 pPresentationParameters->BackBufferWidth = Rect.right;
1925 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1927 if (pPresentationParameters->BackBufferHeight == 0) {
1928 pPresentationParameters->BackBufferHeight = Rect.bottom;
1929 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1931 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1932 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1933 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1937 /* Put the correct figures in the presentation parameters */
1938 TRACE("Copying across presentation parameters\n");
1939 object->presentParms = *pPresentationParameters;
1941 TRACE("calling rendertarget CB\n");
1942 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1943 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1944 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1945 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1946 if (SUCCEEDED(hr)) {
1947 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1948 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1949 if(surface_type == SURFACE_OPENGL) {
1950 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1952 } else {
1953 ERR("Failed to create the front buffer\n");
1954 goto error;
1957 /*********************
1958 * Windowed / Fullscreen
1959 *******************/
1962 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1963 * so we should really check to see if there is a fullscreen swapchain already
1964 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1965 **************************************/
1967 if (!pPresentationParameters->Windowed) {
1968 WINED3DDISPLAYMODE mode;
1971 /* Change the display settings */
1972 mode.Width = pPresentationParameters->BackBufferWidth;
1973 mode.Height = pPresentationParameters->BackBufferHeight;
1974 mode.Format = pPresentationParameters->BackBufferFormat;
1975 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1977 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1978 displaymode_set = TRUE;
1982 * Create an opengl context for the display visual
1983 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1984 * use different properties after that point in time. FIXME: How to handle when requested format
1985 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1986 * it chooses is identical to the one already being used!
1987 **********************************/
1988 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1990 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1991 if(!object->context) {
1992 ERR("Failed to create the context array\n");
1993 hr = E_OUTOFMEMORY;
1994 goto error;
1996 object->num_contexts = 1;
1998 if(surface_type == SURFACE_OPENGL) {
1999 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
2000 if (!object->context[0]) {
2001 ERR("Failed to create a new context\n");
2002 hr = WINED3DERR_NOTAVAILABLE;
2003 goto error;
2004 } else {
2005 TRACE("Context created (HWND=%p, glContext=%p)\n",
2006 object->win_handle, object->context[0]->glCtx);
2010 /*********************
2011 * Create the back, front and stencil buffers
2012 *******************/
2013 if(object->presentParms.BackBufferCount > 0) {
2014 UINT i;
2016 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2017 if(!object->backBuffer) {
2018 ERR("Out of memory\n");
2019 hr = E_OUTOFMEMORY;
2020 goto error;
2023 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2024 TRACE("calling rendertarget CB\n");
2025 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2026 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2027 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2028 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2029 if(SUCCEEDED(hr)) {
2030 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2031 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2032 } else {
2033 ERR("Cannot create new back buffer\n");
2034 goto error;
2036 if(surface_type == SURFACE_OPENGL) {
2037 ENTER_GL();
2038 glDrawBuffer(GL_BACK);
2039 checkGLcall("glDrawBuffer(GL_BACK)");
2040 LEAVE_GL();
2043 } else {
2044 object->backBuffer = NULL;
2046 /* Single buffering - draw to front buffer */
2047 if(surface_type == SURFACE_OPENGL) {
2048 ENTER_GL();
2049 glDrawBuffer(GL_FRONT);
2050 checkGLcall("glDrawBuffer(GL_FRONT)");
2051 LEAVE_GL();
2055 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2056 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2057 TRACE("Creating depth stencil buffer\n");
2058 if (This->auto_depth_stencil_buffer == NULL ) {
2059 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2060 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2061 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2062 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2063 &This->auto_depth_stencil_buffer);
2064 if (SUCCEEDED(hr)) {
2065 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2066 } else {
2067 ERR("Failed to create the auto depth stencil\n");
2068 goto error;
2073 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2075 TRACE("Created swapchain %p\n", object);
2076 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2077 return WINED3D_OK;
2079 error:
2080 if (displaymode_set) {
2081 DEVMODEW devmode;
2082 RECT clip_rc;
2084 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2085 ClipCursor(NULL);
2087 /* Change the display settings */
2088 memset(&devmode, 0, sizeof(devmode));
2089 devmode.dmSize = sizeof(devmode);
2090 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2091 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2092 devmode.dmPelsWidth = object->orig_width;
2093 devmode.dmPelsHeight = object->orig_height;
2094 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2097 if (object->backBuffer) {
2098 UINT i;
2099 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2100 if(object->backBuffer[i]) {
2101 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2102 IUnknown_Release(bufferParent); /* once for the get parent */
2103 if (IUnknown_Release(bufferParent) > 0) {
2104 FIXME("(%p) Something's still holding the back buffer\n",This);
2108 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2109 object->backBuffer = NULL;
2111 if(object->context && object->context[0])
2112 DestroyContext(This, object->context[0]);
2113 if(object->frontBuffer) {
2114 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2115 IUnknown_Release(bufferParent); /* once for the get parent */
2116 if (IUnknown_Release(bufferParent) > 0) {
2117 FIXME("(%p) Something's still holding the front buffer\n",This);
2120 HeapFree(GetProcessHeap(), 0, object);
2121 return hr;
2124 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2125 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 TRACE("(%p)\n", This);
2129 return This->NumberOfSwapChains;
2132 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2134 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2136 if(iSwapChain < This->NumberOfSwapChains) {
2137 *pSwapChain = This->swapchains[iSwapChain];
2138 IWineD3DSwapChain_AddRef(*pSwapChain);
2139 TRACE("(%p) returning %p\n", This, *pSwapChain);
2140 return WINED3D_OK;
2141 } else {
2142 TRACE("Swapchain out of range\n");
2143 *pSwapChain = NULL;
2144 return WINED3DERR_INVALIDCALL;
2148 /*****
2149 * Vertex Declaration
2150 *****/
2151 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2152 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 IWineD3DVertexDeclarationImpl *object = NULL;
2155 HRESULT hr = WINED3D_OK;
2157 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2158 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2160 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2161 if(!object)
2163 ERR("Out of memory\n");
2164 *ppVertexDeclaration = NULL;
2165 return WINED3DERR_OUTOFVIDEOMEMORY;
2168 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2169 object->wineD3DDevice = This;
2170 object->parent = parent;
2171 object->ref = 1;
2173 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2175 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
2176 if(FAILED(hr)) {
2177 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2178 *ppVertexDeclaration = NULL;
2181 return hr;
2184 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2185 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2187 unsigned int idx, idx2;
2188 unsigned int offset;
2189 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2190 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2191 BOOL has_blend_idx = has_blend &&
2192 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2193 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2194 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2195 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2196 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2197 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2198 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2200 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2201 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2203 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
2204 WINED3DVERTEXELEMENT *elements = NULL;
2206 unsigned int size;
2207 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2208 if (has_blend_idx) num_blends--;
2210 /* Compute declaration size */
2211 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2212 has_psize + has_diffuse + has_specular + num_textures + 1;
2214 /* convert the declaration */
2215 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2216 if (!elements)
2217 return 0;
2219 elements[size-1] = end_element;
2220 idx = 0;
2221 if (has_pos) {
2222 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2223 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2224 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2226 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2227 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2228 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2230 else {
2231 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2232 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2234 elements[idx].UsageIndex = 0;
2235 idx++;
2237 if (has_blend && (num_blends > 0)) {
2238 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2239 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2240 else {
2241 switch(num_blends) {
2242 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2243 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2244 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2245 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2246 default:
2247 ERR("Unexpected amount of blend values: %u\n", num_blends);
2250 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2251 elements[idx].UsageIndex = 0;
2252 idx++;
2254 if (has_blend_idx) {
2255 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2256 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2257 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2258 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2259 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2260 else
2261 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2262 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2263 elements[idx].UsageIndex = 0;
2264 idx++;
2266 if (has_normal) {
2267 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2268 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2269 elements[idx].UsageIndex = 0;
2270 idx++;
2272 if (has_psize) {
2273 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2274 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2275 elements[idx].UsageIndex = 0;
2276 idx++;
2278 if (has_diffuse) {
2279 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2280 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2281 elements[idx].UsageIndex = 0;
2282 idx++;
2284 if (has_specular) {
2285 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2286 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2287 elements[idx].UsageIndex = 1;
2288 idx++;
2290 for (idx2 = 0; idx2 < num_textures; idx2++) {
2291 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2292 switch (numcoords) {
2293 case WINED3DFVF_TEXTUREFORMAT1:
2294 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2295 break;
2296 case WINED3DFVF_TEXTUREFORMAT2:
2297 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2298 break;
2299 case WINED3DFVF_TEXTUREFORMAT3:
2300 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2301 break;
2302 case WINED3DFVF_TEXTUREFORMAT4:
2303 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2304 break;
2306 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2307 elements[idx].UsageIndex = idx2;
2308 idx++;
2311 /* Now compute offsets, and initialize the rest of the fields */
2312 for (idx = 0, offset = 0; idx < size-1; idx++) {
2313 elements[idx].Stream = 0;
2314 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2315 elements[idx].Offset = offset;
2316 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2319 *ppVertexElements = elements;
2320 return size;
2323 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2324 WINED3DVERTEXELEMENT* elements = NULL;
2325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2326 unsigned int size;
2327 DWORD hr;
2329 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2330 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2332 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2333 HeapFree(GetProcessHeap(), 0, elements);
2334 if (hr != S_OK) return hr;
2336 return WINED3D_OK;
2339 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2341 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2342 HRESULT hr = WINED3D_OK;
2344 if (!pFunction) return WINED3DERR_INVALIDCALL;
2346 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2347 if (!object)
2349 ERR("Out of memory\n");
2350 *ppVertexShader = NULL;
2351 return WINED3DERR_OUTOFVIDEOMEMORY;
2354 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2355 object->parent = parent;
2356 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2357 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2358 *ppVertexShader = (IWineD3DVertexShader *)object;
2360 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2362 if (vertex_declaration) {
2363 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2366 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2367 if (FAILED(hr))
2369 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2370 IWineD3DVertexShader_Release(*ppVertexShader);
2371 *ppVertexShader = NULL;
2372 return hr;
2375 return hr;
2378 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2381 HRESULT hr = WINED3D_OK;
2383 if (!pFunction) return WINED3DERR_INVALIDCALL;
2385 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2386 if (!object)
2388 ERR("Out of memory\n");
2389 *ppPixelShader = NULL;
2390 return WINED3DERR_OUTOFVIDEOMEMORY;
2393 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2394 object->parent = parent;
2395 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2396 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2397 *ppPixelShader = (IWineD3DPixelShader *)object;
2399 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2401 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2402 if (FAILED(hr))
2404 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2405 IWineD3DPixelShader_Release(*ppPixelShader);
2406 *ppPixelShader = NULL;
2407 return hr;
2410 return hr;
2413 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2414 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2417 IWineD3DPaletteImpl *object;
2418 HRESULT hr;
2419 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2421 /* Create the new object */
2422 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2423 if(!object) {
2424 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2425 return E_OUTOFMEMORY;
2428 object->lpVtbl = &IWineD3DPalette_Vtbl;
2429 object->ref = 1;
2430 object->Flags = Flags;
2431 object->parent = Parent;
2432 object->wineD3DDevice = This;
2433 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2434 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2436 if(!object->hpal) {
2437 HeapFree( GetProcessHeap(), 0, object);
2438 return E_OUTOFMEMORY;
2441 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2442 if(FAILED(hr)) {
2443 IWineD3DPalette_Release((IWineD3DPalette *) object);
2444 return hr;
2447 *Palette = (IWineD3DPalette *) object;
2449 return WINED3D_OK;
2452 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2453 HBITMAP hbm;
2454 BITMAP bm;
2455 HRESULT hr;
2456 HDC dcb = NULL, dcs = NULL;
2457 WINEDDCOLORKEY colorkey;
2459 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2460 if(hbm)
2462 GetObjectA(hbm, sizeof(BITMAP), &bm);
2463 dcb = CreateCompatibleDC(NULL);
2464 if(!dcb) goto out;
2465 SelectObject(dcb, hbm);
2467 else
2469 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2470 * couldn't be loaded
2472 memset(&bm, 0, sizeof(bm));
2473 bm.bmWidth = 32;
2474 bm.bmHeight = 32;
2477 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2478 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2479 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2480 if(FAILED(hr)) {
2481 ERR("Wine logo requested, but failed to create surface\n");
2482 goto out;
2485 if(dcb) {
2486 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2487 if(FAILED(hr)) goto out;
2488 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2489 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2491 colorkey.dwColorSpaceLowValue = 0;
2492 colorkey.dwColorSpaceHighValue = 0;
2493 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2494 } else {
2495 /* Fill the surface with a white color to show that wined3d is there */
2496 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2499 out:
2500 if(dcb) {
2501 DeleteDC(dcb);
2503 if(hbm) {
2504 DeleteObject(hbm);
2506 return;
2509 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2510 unsigned int i;
2511 /* Under DirectX you can have texture stage operations even if no texture is
2512 bound, whereas opengl will only do texture operations when a valid texture is
2513 bound. We emulate this by creating dummy textures and binding them to each
2514 texture stage, but disable all stages by default. Hence if a stage is enabled
2515 then the default texture will kick in until replaced by a SetTexture call */
2516 ENTER_GL();
2518 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2519 /* The dummy texture does not have client storage backing */
2520 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2521 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2523 for (i = 0; i < GL_LIMITS(textures); i++) {
2524 GLubyte white = 255;
2526 /* Make appropriate texture active */
2527 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2528 checkGLcall("glActiveTextureARB");
2530 /* Generate an opengl texture name */
2531 glGenTextures(1, &This->dummyTextureName[i]);
2532 checkGLcall("glGenTextures");
2533 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2535 /* Generate a dummy 2d texture (not using 1d because they cause many
2536 * DRI drivers fall back to sw) */
2537 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2538 checkGLcall("glBindTexture");
2540 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2541 checkGLcall("glTexImage2D");
2543 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2544 /* Reenable because if supported it is enabled by default */
2545 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2546 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2549 LEAVE_GL();
2552 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2553 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2556 IWineD3DSwapChainImpl *swapchain = NULL;
2557 HRESULT hr;
2558 DWORD state;
2559 unsigned int i;
2561 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2563 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2564 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2566 /* TODO: Test if OpenGL is compiled in and loaded */
2568 TRACE("(%p) : Creating stateblock\n", This);
2569 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2570 hr = IWineD3DDevice_CreateStateBlock(iface,
2571 WINED3DSBT_INIT,
2572 (IWineD3DStateBlock **)&This->stateBlock,
2573 NULL);
2574 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2575 WARN("Failed to create stateblock\n");
2576 goto err_out;
2578 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2579 This->updateStateBlock = This->stateBlock;
2580 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2582 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2583 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2585 This->NumberOfPalettes = 1;
2586 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2587 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2588 ERR("Out of memory!\n");
2589 goto err_out;
2591 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2592 if(!This->palettes[0]) {
2593 ERR("Out of memory!\n");
2594 goto err_out;
2596 for (i = 0; i < 256; ++i) {
2597 This->palettes[0][i].peRed = 0xFF;
2598 This->palettes[0][i].peGreen = 0xFF;
2599 This->palettes[0][i].peBlue = 0xFF;
2600 This->palettes[0][i].peFlags = 0xFF;
2602 This->currentPalette = 0;
2604 /* Initialize the texture unit mapping to a 1:1 mapping */
2605 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2606 if (state < GL_LIMITS(fragment_samplers)) {
2607 This->texUnitMap[state] = state;
2608 This->rev_tex_unit_map[state] = state;
2609 } else {
2610 This->texUnitMap[state] = -1;
2611 This->rev_tex_unit_map[state] = -1;
2615 /* Setup the implicit swapchain */
2616 TRACE("Creating implicit swapchain\n");
2617 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2618 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2619 if (FAILED(hr))
2621 WARN("Failed to create implicit swapchain\n");
2622 goto err_out;
2625 This->NumberOfSwapChains = 1;
2626 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2627 if(!This->swapchains) {
2628 ERR("Out of memory!\n");
2629 goto err_out;
2631 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2633 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2634 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2635 This->render_targets[0] = swapchain->backBuffer[0];
2636 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2638 else {
2639 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2640 This->render_targets[0] = swapchain->frontBuffer;
2641 This->lastActiveRenderTarget = swapchain->frontBuffer;
2643 IWineD3DSurface_AddRef(This->render_targets[0]);
2644 This->activeContext = swapchain->context[0];
2645 This->lastThread = GetCurrentThreadId();
2647 /* Depth Stencil support */
2648 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2649 if (NULL != This->stencilBufferTarget) {
2650 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2653 hr = This->shader_backend->shader_alloc_private(iface);
2654 if(FAILED(hr)) {
2655 TRACE("Shader private data couldn't be allocated\n");
2656 goto err_out;
2658 hr = This->frag_pipe->alloc_private(iface);
2659 if(FAILED(hr)) {
2660 TRACE("Fragment pipeline private data couldn't be allocated\n");
2661 goto err_out;
2663 hr = This->blitter->alloc_private(iface);
2664 if(FAILED(hr)) {
2665 TRACE("Blitter private data couldn't be allocated\n");
2666 goto err_out;
2669 /* Set up some starting GL setup */
2671 /* Setup all the devices defaults */
2672 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2673 create_dummy_textures(This);
2675 ENTER_GL();
2677 /* Initialize the current view state */
2678 This->view_ident = 1;
2679 This->contexts[0]->last_was_rhw = 0;
2680 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2681 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2683 switch(wined3d_settings.offscreen_rendering_mode) {
2684 case ORM_FBO:
2685 case ORM_PBUFFER:
2686 This->offscreenBuffer = GL_BACK;
2687 break;
2689 case ORM_BACKBUFFER:
2691 if(This->activeContext->aux_buffers > 0) {
2692 TRACE("Using auxilliary buffer for offscreen rendering\n");
2693 This->offscreenBuffer = GL_AUX0;
2694 } else {
2695 TRACE("Using back buffer for offscreen rendering\n");
2696 This->offscreenBuffer = GL_BACK;
2701 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2702 LEAVE_GL();
2704 /* Clear the screen */
2705 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2706 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2707 0x00, 1.0, 0);
2709 This->d3d_initialized = TRUE;
2711 if(wined3d_settings.logo) {
2712 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2714 This->highest_dirty_ps_const = 0;
2715 This->highest_dirty_vs_const = 0;
2716 return WINED3D_OK;
2718 err_out:
2719 HeapFree(GetProcessHeap(), 0, This->render_targets);
2720 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2721 HeapFree(GetProcessHeap(), 0, This->swapchains);
2722 This->NumberOfSwapChains = 0;
2723 if(This->palettes) {
2724 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2725 HeapFree(GetProcessHeap(), 0, This->palettes);
2727 This->NumberOfPalettes = 0;
2728 if(swapchain) {
2729 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2731 if(This->stateBlock) {
2732 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2733 This->stateBlock = NULL;
2735 if (This->blit_priv) {
2736 This->blitter->free_private(iface);
2738 if (This->fragment_priv) {
2739 This->frag_pipe->free_private(iface);
2741 if (This->shader_priv) {
2742 This->shader_backend->shader_free_private(iface);
2744 return hr;
2747 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2748 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2751 IWineD3DSwapChainImpl *swapchain = NULL;
2752 HRESULT hr;
2754 /* Setup the implicit swapchain */
2755 TRACE("Creating implicit swapchain\n");
2756 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2757 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2758 if (FAILED(hr))
2760 WARN("Failed to create implicit swapchain\n");
2761 goto err_out;
2764 This->NumberOfSwapChains = 1;
2765 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2766 if(!This->swapchains) {
2767 ERR("Out of memory!\n");
2768 goto err_out;
2770 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2771 return WINED3D_OK;
2773 err_out:
2774 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2775 return hr;
2778 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2780 IWineD3DResource_UnLoad(resource);
2781 IWineD3DResource_Release(resource);
2782 return WINED3D_OK;
2785 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2787 int sampler;
2788 UINT i;
2789 TRACE("(%p)\n", This);
2791 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2793 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2794 * it was created. Thus make sure a context is active for the glDelete* calls
2796 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2798 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2800 /* Unload resources */
2801 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2803 TRACE("Deleting high order patches\n");
2804 for(i = 0; i < PATCHMAP_SIZE; i++) {
2805 struct list *e1, *e2;
2806 struct WineD3DRectPatch *patch;
2807 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2808 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2809 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2813 /* Delete the palette conversion shader if it is around */
2814 if(This->paletteConversionShader) {
2815 ENTER_GL();
2816 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2817 LEAVE_GL();
2818 This->paletteConversionShader = 0;
2821 /* Delete the pbuffer context if there is any */
2822 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2824 /* Delete the mouse cursor texture */
2825 if(This->cursorTexture) {
2826 ENTER_GL();
2827 glDeleteTextures(1, &This->cursorTexture);
2828 LEAVE_GL();
2829 This->cursorTexture = 0;
2832 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2833 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2835 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2836 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2839 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2840 * private data, it might contain opengl pointers
2842 if(This->depth_blt_texture) {
2843 glDeleteTextures(1, &This->depth_blt_texture);
2844 This->depth_blt_texture = 0;
2846 if (This->depth_blt_rb) {
2847 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2848 This->depth_blt_rb = 0;
2849 This->depth_blt_rb_w = 0;
2850 This->depth_blt_rb_h = 0;
2853 /* Release the update stateblock */
2854 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2855 if(This->updateStateBlock != This->stateBlock)
2856 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2858 This->updateStateBlock = NULL;
2860 { /* because were not doing proper internal refcounts releasing the primary state block
2861 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2862 to set this->stateBlock = NULL; first */
2863 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2864 This->stateBlock = NULL;
2866 /* Release the stateblock */
2867 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2868 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2872 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2873 This->blitter->free_private(iface);
2874 This->frag_pipe->free_private(iface);
2875 This->shader_backend->shader_free_private(iface);
2877 /* Release the buffers (with sanity checks)*/
2878 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2879 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2880 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2881 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2883 This->stencilBufferTarget = NULL;
2885 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2886 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2887 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2889 TRACE("Setting rendertarget to NULL\n");
2890 This->render_targets[0] = NULL;
2892 if (This->auto_depth_stencil_buffer) {
2893 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2894 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2896 This->auto_depth_stencil_buffer = NULL;
2899 for(i=0; i < This->NumberOfSwapChains; i++) {
2900 TRACE("Releasing the implicit swapchain %d\n", i);
2901 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2902 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2906 HeapFree(GetProcessHeap(), 0, This->swapchains);
2907 This->swapchains = NULL;
2908 This->NumberOfSwapChains = 0;
2910 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2911 HeapFree(GetProcessHeap(), 0, This->palettes);
2912 This->palettes = NULL;
2913 This->NumberOfPalettes = 0;
2915 HeapFree(GetProcessHeap(), 0, This->render_targets);
2916 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2917 This->render_targets = NULL;
2918 This->draw_buffers = NULL;
2920 This->d3d_initialized = FALSE;
2921 return WINED3D_OK;
2924 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2926 unsigned int i;
2928 for(i=0; i < This->NumberOfSwapChains; i++) {
2929 TRACE("Releasing the implicit swapchain %d\n", i);
2930 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2931 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2935 HeapFree(GetProcessHeap(), 0, This->swapchains);
2936 This->swapchains = NULL;
2937 This->NumberOfSwapChains = 0;
2938 return WINED3D_OK;
2941 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2942 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2943 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2945 * There is no way to deactivate thread safety once it is enabled.
2947 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2950 /*For now just store the flag(needed in case of ddraw) */
2951 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2953 return;
2956 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2957 const WINED3DDISPLAYMODE* pMode) {
2958 DEVMODEW devmode;
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 LONG ret;
2961 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2962 RECT clip_rc;
2964 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2966 /* Resize the screen even without a window:
2967 * The app could have unset it with SetCooperativeLevel, but not called
2968 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2969 * but we don't have any hwnd
2972 memset(&devmode, 0, sizeof(devmode));
2973 devmode.dmSize = sizeof(devmode);
2974 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2975 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2976 devmode.dmPelsWidth = pMode->Width;
2977 devmode.dmPelsHeight = pMode->Height;
2979 devmode.dmDisplayFrequency = pMode->RefreshRate;
2980 if (pMode->RefreshRate != 0) {
2981 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2984 /* Only change the mode if necessary */
2985 if( (This->ddraw_width == pMode->Width) &&
2986 (This->ddraw_height == pMode->Height) &&
2987 (This->ddraw_format == pMode->Format) &&
2988 (pMode->RefreshRate == 0) ) {
2989 return WINED3D_OK;
2992 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2993 if (ret != DISP_CHANGE_SUCCESSFUL) {
2994 if(devmode.dmDisplayFrequency != 0) {
2995 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2996 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2997 devmode.dmDisplayFrequency = 0;
2998 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
3000 if(ret != DISP_CHANGE_SUCCESSFUL) {
3001 return WINED3DERR_NOTAVAILABLE;
3005 /* Store the new values */
3006 This->ddraw_width = pMode->Width;
3007 This->ddraw_height = pMode->Height;
3008 This->ddraw_format = pMode->Format;
3010 /* And finally clip mouse to our screen */
3011 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3012 ClipCursor(&clip_rc);
3014 return WINED3D_OK;
3017 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 *ppD3D= This->wineD3D;
3020 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3021 IWineD3D_AddRef(*ppD3D);
3022 return WINED3D_OK;
3025 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3029 (This->adapter->TextureRam/(1024*1024)),
3030 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3031 /* return simulated texture memory left */
3032 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3035 /*****
3036 * Get / Set Stream Source
3037 *****/
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3039 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 IWineD3DBuffer *oldSrc;
3044 if (StreamNumber >= MAX_STREAMS) {
3045 WARN("Stream out of range %d\n", StreamNumber);
3046 return WINED3DERR_INVALIDCALL;
3047 } else if(OffsetInBytes & 0x3) {
3048 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3049 return WINED3DERR_INVALIDCALL;
3052 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3053 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3055 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3057 if(oldSrc == pStreamData &&
3058 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3059 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3060 TRACE("Application is setting the old values over, nothing to do\n");
3061 return WINED3D_OK;
3064 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3065 if (pStreamData) {
3066 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3067 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3070 /* Handle recording of state blocks */
3071 if (This->isRecordingState) {
3072 TRACE("Recording... not performing anything\n");
3073 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3074 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3075 return WINED3D_OK;
3078 if (pStreamData != NULL) {
3079 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3080 IWineD3DBuffer_AddRef(pStreamData);
3082 if (oldSrc != NULL) {
3083 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3084 IWineD3DBuffer_Release(oldSrc);
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3089 return WINED3D_OK;
3092 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3093 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3098 This->stateBlock->streamSource[StreamNumber],
3099 This->stateBlock->streamOffset[StreamNumber],
3100 This->stateBlock->streamStride[StreamNumber]);
3102 if (StreamNumber >= MAX_STREAMS) {
3103 WARN("Stream out of range %d\n", StreamNumber);
3104 return WINED3DERR_INVALIDCALL;
3106 *pStream = This->stateBlock->streamSource[StreamNumber];
3107 *pStride = This->stateBlock->streamStride[StreamNumber];
3108 if (pOffset) {
3109 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3112 if (*pStream != NULL) {
3113 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3115 return WINED3D_OK;
3118 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3121 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3123 /* Verify input at least in d3d9 this is invalid*/
3124 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3125 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3126 return WINED3DERR_INVALIDCALL;
3128 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3129 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3130 return WINED3DERR_INVALIDCALL;
3132 if( Divider == 0 ){
3133 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3134 return WINED3DERR_INVALIDCALL;
3137 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3138 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3140 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3141 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3143 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3144 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3148 return WINED3D_OK;
3151 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3155 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3157 TRACE("(%p) : returning %d\n", This, *Divider);
3159 return WINED3D_OK;
3162 /*****
3163 * Get / Set & Multiply Transform
3164 *****/
3165 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 /* Most of this routine, comments included copied from ddraw tree initially: */
3169 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3171 /* Handle recording of state blocks */
3172 if (This->isRecordingState) {
3173 TRACE("Recording... not performing anything\n");
3174 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3175 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3176 return WINED3D_OK;
3180 * If the new matrix is the same as the current one,
3181 * we cut off any further processing. this seems to be a reasonable
3182 * optimization because as was noticed, some apps (warcraft3 for example)
3183 * tend towards setting the same matrix repeatedly for some reason.
3185 * From here on we assume that the new matrix is different, wherever it matters.
3187 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3188 TRACE("The app is setting the same matrix over again\n");
3189 return WINED3D_OK;
3190 } else {
3191 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3195 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3196 where ViewMat = Camera space, WorldMat = world space.
3198 In OpenGL, camera and world space is combined into GL_MODELVIEW
3199 matrix. The Projection matrix stay projection matrix.
3202 /* Capture the times we can just ignore the change for now */
3203 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3204 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3205 /* Handled by the state manager */
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3209 return WINED3D_OK;
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3215 *pMatrix = This->stateBlock->transforms[State];
3216 return WINED3D_OK;
3219 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3220 const WINED3DMATRIX *mat = NULL;
3221 WINED3DMATRIX temp;
3223 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3224 * below means it will be recorded in a state block change, but it
3225 * works regardless where it is recorded.
3226 * If this is found to be wrong, change to StateBlock.
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3231 if (State <= HIGHEST_TRANSFORMSTATE)
3233 mat = &This->updateStateBlock->transforms[State];
3234 } else {
3235 FIXME("Unhandled transform state!!\n");
3238 multiply_matrix(&temp, mat, pMatrix);
3240 /* Apply change via set transform - will reapply to eg. lights this way */
3241 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3244 /*****
3245 * Get / Set Light
3246 *****/
3247 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3248 you can reference any indexes you want as long as that number max are enabled at any
3249 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3250 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3251 but when recording, just build a chain pretty much of commands to be replayed. */
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3254 float rho;
3255 PLIGHTINFOEL *object = NULL;
3256 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3257 struct list *e;
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3262 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3263 * the gl driver.
3265 if(!pLight) {
3266 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3267 return WINED3DERR_INVALIDCALL;
3270 switch(pLight->Type) {
3271 case WINED3DLIGHT_POINT:
3272 case WINED3DLIGHT_SPOT:
3273 case WINED3DLIGHT_PARALLELPOINT:
3274 case WINED3DLIGHT_GLSPOT:
3275 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3276 * most wanted
3278 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3279 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3280 return WINED3DERR_INVALIDCALL;
3282 break;
3284 case WINED3DLIGHT_DIRECTIONAL:
3285 /* Ignores attenuation */
3286 break;
3288 default:
3289 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3290 return WINED3DERR_INVALIDCALL;
3293 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3294 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3295 if(object->OriginalIndex == Index) break;
3296 object = NULL;
3299 if(!object) {
3300 TRACE("Adding new light\n");
3301 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3302 if(!object) {
3303 ERR("Out of memory error when allocating a light\n");
3304 return E_OUTOFMEMORY;
3306 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3307 object->glIndex = -1;
3308 object->OriginalIndex = Index;
3309 object->changed = TRUE;
3312 /* Initialize the object */
3313 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,
3314 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3315 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3316 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3317 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3318 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3319 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3321 /* Save away the information */
3322 object->OriginalParms = *pLight;
3324 switch (pLight->Type) {
3325 case WINED3DLIGHT_POINT:
3326 /* Position */
3327 object->lightPosn[0] = pLight->Position.x;
3328 object->lightPosn[1] = pLight->Position.y;
3329 object->lightPosn[2] = pLight->Position.z;
3330 object->lightPosn[3] = 1.0f;
3331 object->cutoff = 180.0f;
3332 /* FIXME: Range */
3333 break;
3335 case WINED3DLIGHT_DIRECTIONAL:
3336 /* Direction */
3337 object->lightPosn[0] = -pLight->Direction.x;
3338 object->lightPosn[1] = -pLight->Direction.y;
3339 object->lightPosn[2] = -pLight->Direction.z;
3340 object->lightPosn[3] = 0.0;
3341 object->exponent = 0.0f;
3342 object->cutoff = 180.0f;
3343 break;
3345 case WINED3DLIGHT_SPOT:
3346 /* Position */
3347 object->lightPosn[0] = pLight->Position.x;
3348 object->lightPosn[1] = pLight->Position.y;
3349 object->lightPosn[2] = pLight->Position.z;
3350 object->lightPosn[3] = 1.0;
3352 /* Direction */
3353 object->lightDirn[0] = pLight->Direction.x;
3354 object->lightDirn[1] = pLight->Direction.y;
3355 object->lightDirn[2] = pLight->Direction.z;
3356 object->lightDirn[3] = 1.0;
3359 * opengl-ish and d3d-ish spot lights use too different models for the
3360 * light "intensity" as a function of the angle towards the main light direction,
3361 * so we only can approximate very roughly.
3362 * however spot lights are rather rarely used in games (if ever used at all).
3363 * furthermore if still used, probably nobody pays attention to such details.
3365 if (pLight->Falloff == 0) {
3366 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3367 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3368 * will always be 1.0 for both of them, and we don't have to care for the
3369 * rest of the rather complex calculation
3371 object->exponent = 0;
3372 } else {
3373 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3374 if (rho < 0.0001) rho = 0.0001f;
3375 object->exponent = -0.3/log(cos(rho/2));
3377 if (object->exponent > 128.0) {
3378 object->exponent = 128.0;
3380 object->cutoff = pLight->Phi*90/M_PI;
3382 /* FIXME: Range */
3383 break;
3385 default:
3386 FIXME("Unrecognized light type %d\n", pLight->Type);
3389 /* Update the live definitions if the light is currently assigned a glIndex */
3390 if (object->glIndex != -1 && !This->isRecordingState) {
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3393 return WINED3D_OK;
3396 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3397 PLIGHTINFOEL *lightInfo = NULL;
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3400 struct list *e;
3401 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3403 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3404 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3405 if(lightInfo->OriginalIndex == Index) break;
3406 lightInfo = NULL;
3409 if (lightInfo == NULL) {
3410 TRACE("Light information requested but light not defined\n");
3411 return WINED3DERR_INVALIDCALL;
3414 *pLight = lightInfo->OriginalParms;
3415 return WINED3D_OK;
3418 /*****
3419 * Get / Set Light Enable
3420 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3421 *****/
3422 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3423 PLIGHTINFOEL *lightInfo = NULL;
3424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3425 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3426 struct list *e;
3427 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3429 /* Tests show true = 128...not clear why */
3430 Enable = Enable? 128: 0;
3432 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3433 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3434 if(lightInfo->OriginalIndex == Index) break;
3435 lightInfo = NULL;
3437 TRACE("Found light: %p\n", lightInfo);
3439 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3440 if (lightInfo == NULL) {
3442 TRACE("Light enabled requested but light not defined, so defining one!\n");
3443 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3445 /* Search for it again! Should be fairly quick as near head of list */
3446 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3447 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3448 if(lightInfo->OriginalIndex == Index) break;
3449 lightInfo = NULL;
3451 if (lightInfo == NULL) {
3452 FIXME("Adding default lights has failed dismally\n");
3453 return WINED3DERR_INVALIDCALL;
3457 lightInfo->enabledChanged = TRUE;
3458 if(!Enable) {
3459 if(lightInfo->glIndex != -1) {
3460 if(!This->isRecordingState) {
3461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3464 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3465 lightInfo->glIndex = -1;
3466 } else {
3467 TRACE("Light already disabled, nothing to do\n");
3469 lightInfo->enabled = FALSE;
3470 } else {
3471 lightInfo->enabled = TRUE;
3472 if (lightInfo->glIndex != -1) {
3473 /* nop */
3474 TRACE("Nothing to do as light was enabled\n");
3475 } else {
3476 int i;
3477 /* Find a free gl light */
3478 for(i = 0; i < This->maxConcurrentLights; i++) {
3479 if(This->updateStateBlock->activeLights[i] == NULL) {
3480 This->updateStateBlock->activeLights[i] = lightInfo;
3481 lightInfo->glIndex = i;
3482 break;
3485 if(lightInfo->glIndex == -1) {
3486 /* Our tests show that Windows returns D3D_OK in this situation, even with
3487 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3488 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3489 * as well for those lights.
3491 * TODO: Test how this affects rendering
3493 WARN("Too many concurrently active lights\n");
3494 return WINED3D_OK;
3497 /* i == lightInfo->glIndex */
3498 if(!This->isRecordingState) {
3499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3504 return WINED3D_OK;
3507 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3509 PLIGHTINFOEL *lightInfo = NULL;
3510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3511 struct list *e;
3512 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3513 TRACE("(%p) : for idx(%d)\n", This, Index);
3515 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3516 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3517 if(lightInfo->OriginalIndex == Index) break;
3518 lightInfo = NULL;
3521 if (lightInfo == NULL) {
3522 TRACE("Light enabled state requested but light not defined\n");
3523 return WINED3DERR_INVALIDCALL;
3525 /* true is 128 according to SetLightEnable */
3526 *pEnable = lightInfo->enabled ? 128 : 0;
3527 return WINED3D_OK;
3530 /*****
3531 * Get / Set Clip Planes
3532 *****/
3533 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3535 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3537 /* Validate Index */
3538 if (Index >= GL_LIMITS(clipplanes)) {
3539 TRACE("Application has requested clipplane this device doesn't support\n");
3540 return WINED3DERR_INVALIDCALL;
3543 This->updateStateBlock->changed.clipplane |= 1 << Index;
3545 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3546 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3547 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3548 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3549 TRACE("Application is setting old values over, nothing to do\n");
3550 return WINED3D_OK;
3553 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3554 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3555 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3556 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3558 /* Handle recording of state blocks */
3559 if (This->isRecordingState) {
3560 TRACE("Recording... not performing anything\n");
3561 return WINED3D_OK;
3564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3566 return WINED3D_OK;
3569 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 TRACE("(%p) : for idx %d\n", This, Index);
3573 /* Validate Index */
3574 if (Index >= GL_LIMITS(clipplanes)) {
3575 TRACE("Application has requested clipplane this device doesn't support\n");
3576 return WINED3DERR_INVALIDCALL;
3579 pPlane[0] = This->stateBlock->clipplane[Index][0];
3580 pPlane[1] = This->stateBlock->clipplane[Index][1];
3581 pPlane[2] = This->stateBlock->clipplane[Index][2];
3582 pPlane[3] = This->stateBlock->clipplane[Index][3];
3583 return WINED3D_OK;
3586 /*****
3587 * Get / Set Clip Plane Status
3588 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3589 *****/
3590 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3592 FIXME("(%p) : stub\n", This);
3593 if (NULL == pClipStatus) {
3594 return WINED3DERR_INVALIDCALL;
3596 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3597 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3598 return WINED3D_OK;
3601 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 FIXME("(%p) : stub\n", This);
3604 if (NULL == pClipStatus) {
3605 return WINED3DERR_INVALIDCALL;
3607 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3608 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3609 return WINED3D_OK;
3612 /*****
3613 * Get / Set Material
3614 *****/
3615 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3618 This->updateStateBlock->changed.material = TRUE;
3619 This->updateStateBlock->material = *pMaterial;
3621 /* Handle recording of state blocks */
3622 if (This->isRecordingState) {
3623 TRACE("Recording... not performing anything\n");
3624 return WINED3D_OK;
3627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3628 return WINED3D_OK;
3631 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3633 *pMaterial = This->updateStateBlock->material;
3634 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3635 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3636 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3637 pMaterial->Ambient.b, pMaterial->Ambient.a);
3638 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3639 pMaterial->Specular.b, pMaterial->Specular.a);
3640 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3641 pMaterial->Emissive.b, pMaterial->Emissive.a);
3642 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3644 return WINED3D_OK;
3647 /*****
3648 * Get / Set Indices
3649 *****/
3650 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3652 IWineD3DIndexBuffer *oldIdxs;
3654 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3655 oldIdxs = This->updateStateBlock->pIndexData;
3657 This->updateStateBlock->changed.indices = TRUE;
3658 This->updateStateBlock->pIndexData = pIndexData;
3660 /* Handle recording of state blocks */
3661 if (This->isRecordingState) {
3662 TRACE("Recording... not performing anything\n");
3663 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3664 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3665 return WINED3D_OK;
3668 if(oldIdxs != pIndexData) {
3669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3670 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3671 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3673 return WINED3D_OK;
3676 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 *ppIndexData = This->stateBlock->pIndexData;
3681 /* up ref count on ppindexdata */
3682 if (*ppIndexData) {
3683 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3684 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3685 }else{
3686 TRACE("(%p) No index data set\n", This);
3688 TRACE("Returning %p\n", *ppIndexData);
3690 return WINED3D_OK;
3693 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3694 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3696 TRACE("(%p)->(%d)\n", This, BaseIndex);
3698 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3699 TRACE("Application is setting the old value over, nothing to do\n");
3700 return WINED3D_OK;
3703 This->updateStateBlock->baseVertexIndex = BaseIndex;
3705 if (This->isRecordingState) {
3706 TRACE("Recording... not performing anything\n");
3707 return WINED3D_OK;
3709 /* The base vertex index affects the stream sources */
3710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3711 return WINED3D_OK;
3714 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3716 TRACE("(%p) : base_index %p\n", This, base_index);
3718 *base_index = This->stateBlock->baseVertexIndex;
3720 TRACE("Returning %u\n", *base_index);
3722 return WINED3D_OK;
3725 /*****
3726 * Get / Set Viewports
3727 *****/
3728 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3731 TRACE("(%p)\n", This);
3732 This->updateStateBlock->changed.viewport = TRUE;
3733 This->updateStateBlock->viewport = *pViewport;
3735 /* Handle recording of state blocks */
3736 if (This->isRecordingState) {
3737 TRACE("Recording... not performing anything\n");
3738 return WINED3D_OK;
3741 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3742 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3745 return WINED3D_OK;
3749 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 TRACE("(%p)\n", This);
3752 *pViewport = This->stateBlock->viewport;
3753 return WINED3D_OK;
3756 /*****
3757 * Get / Set Render States
3758 * TODO: Verify against dx9 definitions
3759 *****/
3760 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3763 DWORD oldValue = This->stateBlock->renderState[State];
3765 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3767 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3768 This->updateStateBlock->renderState[State] = Value;
3770 /* Handle recording of state blocks */
3771 if (This->isRecordingState) {
3772 TRACE("Recording... not performing anything\n");
3773 return WINED3D_OK;
3776 /* Compared here and not before the assignment to allow proper stateblock recording */
3777 if(Value == oldValue) {
3778 TRACE("Application is setting the old value over, nothing to do\n");
3779 } else {
3780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3783 return WINED3D_OK;
3786 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3789 *pValue = This->stateBlock->renderState[State];
3790 return WINED3D_OK;
3793 /*****
3794 * Get / Set Sampler States
3795 * TODO: Verify against dx9 definitions
3796 *****/
3798 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3800 DWORD oldValue;
3802 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3803 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3805 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3806 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3809 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3810 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3811 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3814 * SetSampler is designed to allow for more than the standard up to 8 textures
3815 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3816 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3818 * http://developer.nvidia.com/object/General_FAQ.html#t6
3820 * There are two new settings for GForce
3821 * the sampler one:
3822 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3823 * and the texture one:
3824 * GL_MAX_TEXTURE_COORDS_ARB.
3825 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3826 ******************/
3828 oldValue = This->stateBlock->samplerState[Sampler][Type];
3829 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3830 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3832 /* Handle recording of state blocks */
3833 if (This->isRecordingState) {
3834 TRACE("Recording... not performing anything\n");
3835 return WINED3D_OK;
3838 if(oldValue == Value) {
3839 TRACE("Application is setting the old value over, nothing to do\n");
3840 return WINED3D_OK;
3843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3845 return WINED3D_OK;
3848 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3851 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3852 This, Sampler, debug_d3dsamplerstate(Type), Type);
3854 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3855 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3858 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3859 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3860 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3862 *Value = This->stateBlock->samplerState[Sampler][Type];
3863 TRACE("(%p) : Returning %#x\n", This, *Value);
3865 return WINED3D_OK;
3868 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3871 This->updateStateBlock->changed.scissorRect = TRUE;
3872 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3873 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3874 return WINED3D_OK;
3876 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3878 if(This->isRecordingState) {
3879 TRACE("Recording... not performing anything\n");
3880 return WINED3D_OK;
3883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3885 return WINED3D_OK;
3888 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3891 *pRect = This->updateStateBlock->scissorRect;
3892 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3893 return WINED3D_OK;
3896 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3898 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3900 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3902 This->updateStateBlock->vertexDecl = pDecl;
3903 This->updateStateBlock->changed.vertexDecl = TRUE;
3905 if (This->isRecordingState) {
3906 TRACE("Recording... not performing anything\n");
3907 return WINED3D_OK;
3908 } else if(pDecl == oldDecl) {
3909 /* Checked after the assignment to allow proper stateblock recording */
3910 TRACE("Application is setting the old declaration over, nothing to do\n");
3911 return WINED3D_OK;
3914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3915 return WINED3D_OK;
3918 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3921 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3923 *ppDecl = This->stateBlock->vertexDecl;
3924 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3925 return WINED3D_OK;
3928 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3930 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3932 This->updateStateBlock->vertexShader = pShader;
3933 This->updateStateBlock->changed.vertexShader = TRUE;
3935 if (This->isRecordingState) {
3936 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3937 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3938 TRACE("Recording... not performing anything\n");
3939 return WINED3D_OK;
3940 } else if(oldShader == pShader) {
3941 /* Checked here to allow proper stateblock recording */
3942 TRACE("App is setting the old shader over, nothing to do\n");
3943 return WINED3D_OK;
3946 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3947 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3948 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3952 return WINED3D_OK;
3955 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 if (NULL == ppShader) {
3959 return WINED3DERR_INVALIDCALL;
3961 *ppShader = This->stateBlock->vertexShader;
3962 if( NULL != *ppShader)
3963 IWineD3DVertexShader_AddRef(*ppShader);
3965 TRACE("(%p) : returning %p\n", This, *ppShader);
3966 return WINED3D_OK;
3969 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3970 IWineD3DDevice *iface,
3971 UINT start,
3972 CONST BOOL *srcData,
3973 UINT count) {
3975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3976 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3978 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3979 iface, srcData, start, count);
3981 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3983 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3984 for (i = 0; i < cnt; i++)
3985 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3987 for (i = start; i < cnt + start; ++i) {
3988 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3991 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3993 return WINED3D_OK;
3996 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3997 IWineD3DDevice *iface,
3998 UINT start,
3999 BOOL *dstData,
4000 UINT count) {
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003 int cnt = min(count, MAX_CONST_B - start);
4005 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4006 iface, dstData, start, count);
4008 if (dstData == NULL || cnt < 0)
4009 return WINED3DERR_INVALIDCALL;
4011 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4012 return WINED3D_OK;
4015 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4016 IWineD3DDevice *iface,
4017 UINT start,
4018 CONST int *srcData,
4019 UINT count) {
4021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4022 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4024 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4025 iface, srcData, start, count);
4027 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4029 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4030 for (i = 0; i < cnt; i++)
4031 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4032 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4034 for (i = start; i < cnt + start; ++i) {
4035 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4038 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4040 return WINED3D_OK;
4043 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4044 IWineD3DDevice *iface,
4045 UINT start,
4046 int *dstData,
4047 UINT count) {
4049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4050 int cnt = min(count, MAX_CONST_I - start);
4052 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4053 iface, dstData, start, count);
4055 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4056 return WINED3DERR_INVALIDCALL;
4058 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4059 return WINED3D_OK;
4062 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4063 IWineD3DDevice *iface,
4064 UINT start,
4065 CONST float *srcData,
4066 UINT count) {
4068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4069 UINT i;
4071 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4072 iface, srcData, start, count);
4074 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4075 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
4076 return WINED3DERR_INVALIDCALL;
4078 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4079 if(TRACE_ON(d3d)) {
4080 for (i = 0; i < count; i++)
4081 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4082 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4085 if (!This->isRecordingState)
4087 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4091 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4092 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4094 return WINED3D_OK;
4097 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4098 IWineD3DDevice *iface,
4099 UINT start,
4100 float *dstData,
4101 UINT count) {
4103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4106 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4107 iface, dstData, start, count);
4109 if (dstData == NULL || cnt < 0)
4110 return WINED3DERR_INVALIDCALL;
4112 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4113 return WINED3D_OK;
4116 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4117 DWORD i;
4118 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4124 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4125 int i = This->rev_tex_unit_map[unit];
4126 int j = This->texUnitMap[stage];
4128 This->texUnitMap[stage] = unit;
4129 if (i != -1 && i != stage) {
4130 This->texUnitMap[i] = -1;
4133 This->rev_tex_unit_map[unit] = stage;
4134 if (j != -1 && j != unit) {
4135 This->rev_tex_unit_map[j] = -1;
4139 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4140 int i;
4142 This->fixed_function_usage_map = 0;
4143 for (i = 0; i < MAX_TEXTURES; ++i) {
4144 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4145 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4146 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4147 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4148 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4149 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4150 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4151 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4153 if (color_op == WINED3DTOP_DISABLE) {
4154 /* Not used, and disable higher stages */
4155 break;
4158 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4159 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4160 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4161 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4162 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4163 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4164 This->fixed_function_usage_map |= (1 << i);
4167 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4168 This->fixed_function_usage_map |= (1 << (i + 1));
4173 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4174 unsigned int i, tex;
4175 WORD ffu_map;
4177 device_update_fixed_function_usage_map(This);
4178 ffu_map = This->fixed_function_usage_map;
4180 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4181 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4182 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4184 if (!(ffu_map & 1)) continue;
4186 if (This->texUnitMap[i] != i) {
4187 device_map_stage(This, i, i);
4188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4189 markTextureStagesDirty(This, i);
4192 return;
4195 /* Now work out the mapping */
4196 tex = 0;
4197 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4199 if (!(ffu_map & 1)) continue;
4201 if (This->texUnitMap[i] != tex) {
4202 device_map_stage(This, i, tex);
4203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4204 markTextureStagesDirty(This, i);
4207 ++tex;
4211 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4212 const DWORD *sampler_tokens =
4213 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4214 unsigned int i;
4216 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4217 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4218 device_map_stage(This, i, i);
4219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4220 if (i < MAX_TEXTURES) {
4221 markTextureStagesDirty(This, i);
4227 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4228 const DWORD *vshader_sampler_tokens, int unit)
4230 int current_mapping = This->rev_tex_unit_map[unit];
4232 if (current_mapping == -1) {
4233 /* Not currently used */
4234 return TRUE;
4237 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4238 /* Used by a fragment sampler */
4240 if (!pshader_sampler_tokens) {
4241 /* No pixel shader, check fixed function */
4242 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4245 /* Pixel shader, check the shader's sampler map */
4246 return !pshader_sampler_tokens[current_mapping];
4249 /* Used by a vertex sampler */
4250 return !vshader_sampler_tokens[current_mapping];
4253 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4254 const DWORD *vshader_sampler_tokens =
4255 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4256 const DWORD *pshader_sampler_tokens = NULL;
4257 int start = GL_LIMITS(combined_samplers) - 1;
4258 int i;
4260 if (ps) {
4261 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4263 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4264 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4265 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4268 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4269 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4270 if (vshader_sampler_tokens[i]) {
4271 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4273 /* Already mapped somewhere */
4274 continue;
4277 while (start >= 0) {
4278 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4279 device_map_stage(This, vsampler_idx, start);
4280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4282 --start;
4283 break;
4286 --start;
4292 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4293 BOOL vs = use_vs(This->stateBlock);
4294 BOOL ps = use_ps(This->stateBlock);
4296 * Rules are:
4297 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4298 * that would be really messy and require shader recompilation
4299 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4300 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4302 if (ps) {
4303 device_map_psamplers(This);
4304 } else {
4305 device_map_fixed_function_samplers(This);
4308 if (vs) {
4309 device_map_vsamplers(This, ps);
4313 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4315 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4316 This->updateStateBlock->pixelShader = pShader;
4317 This->updateStateBlock->changed.pixelShader = TRUE;
4319 /* Handle recording of state blocks */
4320 if (This->isRecordingState) {
4321 TRACE("Recording... not performing anything\n");
4324 if (This->isRecordingState) {
4325 TRACE("Recording... not performing anything\n");
4326 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4327 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4328 return WINED3D_OK;
4331 if(pShader == oldShader) {
4332 TRACE("App is setting the old pixel shader over, nothing to do\n");
4333 return WINED3D_OK;
4336 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4337 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4339 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4340 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4342 return WINED3D_OK;
4345 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4348 if (NULL == ppShader) {
4349 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4350 return WINED3DERR_INVALIDCALL;
4353 *ppShader = This->stateBlock->pixelShader;
4354 if (NULL != *ppShader) {
4355 IWineD3DPixelShader_AddRef(*ppShader);
4357 TRACE("(%p) : returning %p\n", This, *ppShader);
4358 return WINED3D_OK;
4361 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4362 IWineD3DDevice *iface,
4363 UINT start,
4364 CONST BOOL *srcData,
4365 UINT count) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4370 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4371 iface, srcData, start, count);
4373 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4375 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4376 for (i = 0; i < cnt; i++)
4377 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4379 for (i = start; i < cnt + start; ++i) {
4380 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4383 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4385 return WINED3D_OK;
4388 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4389 IWineD3DDevice *iface,
4390 UINT start,
4391 BOOL *dstData,
4392 UINT count) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 int cnt = min(count, MAX_CONST_B - start);
4397 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4398 iface, dstData, start, count);
4400 if (dstData == NULL || cnt < 0)
4401 return WINED3DERR_INVALIDCALL;
4403 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4404 return WINED3D_OK;
4407 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4408 IWineD3DDevice *iface,
4409 UINT start,
4410 CONST int *srcData,
4411 UINT count) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4416 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4417 iface, srcData, start, count);
4419 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4421 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4422 for (i = 0; i < cnt; i++)
4423 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4424 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4426 for (i = start; i < cnt + start; ++i) {
4427 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4430 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4432 return WINED3D_OK;
4435 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4436 IWineD3DDevice *iface,
4437 UINT start,
4438 int *dstData,
4439 UINT count) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 int cnt = min(count, MAX_CONST_I - start);
4444 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4445 iface, dstData, start, count);
4447 if (dstData == NULL || cnt < 0)
4448 return WINED3DERR_INVALIDCALL;
4450 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4451 return WINED3D_OK;
4454 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4455 IWineD3DDevice *iface,
4456 UINT start,
4457 CONST float *srcData,
4458 UINT count) {
4460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4461 UINT i;
4463 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4464 iface, srcData, start, count);
4466 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4467 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4468 return WINED3DERR_INVALIDCALL;
4470 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4471 if(TRACE_ON(d3d)) {
4472 for (i = 0; i < count; i++)
4473 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4474 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4477 if (!This->isRecordingState)
4479 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4483 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4484 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4486 return WINED3D_OK;
4489 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4490 IWineD3DDevice *iface,
4491 UINT start,
4492 float *dstData,
4493 UINT count) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4498 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4499 iface, dstData, start, count);
4501 if (dstData == NULL || cnt < 0)
4502 return WINED3DERR_INVALIDCALL;
4504 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4505 return WINED3D_OK;
4508 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4509 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4510 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags)
4512 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4513 unsigned int i;
4514 DWORD DestFVF = dest->fvf;
4515 WINED3DVIEWPORT vp;
4516 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4517 BOOL doClip;
4518 DWORD numTextures;
4520 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4522 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4525 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4527 ERR("Source has no position mask\n");
4528 return WINED3DERR_INVALIDCALL;
4531 /* We might access VBOs from this code, so hold the lock */
4532 ENTER_GL();
4534 if (dest->resource.allocatedMemory == NULL) {
4535 /* This may happen if we do direct locking into a vbo. Unlikely,
4536 * but theoretically possible(ddraw processvertices test)
4538 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4539 if(!dest->resource.allocatedMemory) {
4540 LEAVE_GL();
4541 ERR("Out of memory\n");
4542 return E_OUTOFMEMORY;
4544 if (dest->buffer_object)
4546 const void *src;
4547 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4548 checkGLcall("glBindBufferARB");
4549 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4550 if(src) {
4551 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4553 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4554 checkGLcall("glUnmapBufferARB");
4558 /* Get a pointer into the destination vbo(create one if none exists) and
4559 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4561 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4563 dest->flags |= WINED3D_BUFFER_CREATEBO;
4564 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4567 if (dest->buffer_object)
4569 unsigned char extrabytes = 0;
4570 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4571 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4572 * this may write 4 extra bytes beyond the area that should be written
4574 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4575 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4576 if(!dest_conv_addr) {
4577 ERR("Out of memory\n");
4578 /* Continue without storing converted vertices */
4580 dest_conv = dest_conv_addr;
4583 /* Should I clip?
4584 * a) WINED3DRS_CLIPPING is enabled
4585 * b) WINED3DVOP_CLIP is passed
4587 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4588 static BOOL warned = FALSE;
4590 * The clipping code is not quite correct. Some things need
4591 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4592 * so disable clipping for now.
4593 * (The graphics in Half-Life are broken, and my processvertices
4594 * test crashes with IDirect3DDevice3)
4595 doClip = TRUE;
4597 doClip = FALSE;
4598 if(!warned) {
4599 warned = TRUE;
4600 FIXME("Clipping is broken and disabled for now\n");
4602 } else doClip = FALSE;
4603 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4605 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4606 WINED3DTS_VIEW,
4607 &view_mat);
4608 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4609 WINED3DTS_PROJECTION,
4610 &proj_mat);
4611 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4612 WINED3DTS_WORLDMATRIX(0),
4613 &world_mat);
4615 TRACE("View mat:\n");
4616 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);
4617 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);
4618 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);
4619 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);
4621 TRACE("Proj mat:\n");
4622 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);
4623 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);
4624 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);
4625 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);
4627 TRACE("World mat:\n");
4628 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);
4629 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);
4630 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);
4631 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);
4633 /* Get the viewport */
4634 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4635 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4636 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4638 multiply_matrix(&mat,&view_mat,&world_mat);
4639 multiply_matrix(&mat,&proj_mat,&mat);
4641 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4643 for (i = 0; i < dwCount; i+= 1) {
4644 unsigned int tex_index;
4646 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4647 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4648 /* The position first */
4649 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4650 const float *p = (const float *)(element->data + i * element->stride);
4651 float x, y, z, rhw;
4652 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4654 /* Multiplication with world, view and projection matrix */
4655 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);
4656 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);
4657 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);
4658 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);
4660 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4662 /* WARNING: The following things are taken from d3d7 and were not yet checked
4663 * against d3d8 or d3d9!
4666 /* Clipping conditions: From msdn
4668 * A vertex is clipped if it does not match the following requirements
4669 * -rhw < x <= rhw
4670 * -rhw < y <= rhw
4671 * 0 < z <= rhw
4672 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4674 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4675 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4679 if( !doClip ||
4680 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4681 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4682 ( rhw > eps ) ) ) {
4684 /* "Normal" viewport transformation (not clipped)
4685 * 1) The values are divided by rhw
4686 * 2) The y axis is negative, so multiply it with -1
4687 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4688 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4689 * 4) Multiply x with Width/2 and add Width/2
4690 * 5) The same for the height
4691 * 6) Add the viewpoint X and Y to the 2D coordinates and
4692 * The minimum Z value to z
4693 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4695 * Well, basically it's simply a linear transformation into viewport
4696 * coordinates
4699 x /= rhw;
4700 y /= rhw;
4701 z /= rhw;
4703 y *= -1;
4705 x *= vp.Width / 2;
4706 y *= vp.Height / 2;
4707 z *= vp.MaxZ - vp.MinZ;
4709 x += vp.Width / 2 + vp.X;
4710 y += vp.Height / 2 + vp.Y;
4711 z += vp.MinZ;
4713 rhw = 1 / rhw;
4714 } else {
4715 /* That vertex got clipped
4716 * Contrary to OpenGL it is not dropped completely, it just
4717 * undergoes a different calculation.
4719 TRACE("Vertex got clipped\n");
4720 x += rhw;
4721 y += rhw;
4723 x /= 2;
4724 y /= 2;
4726 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4727 * outside of the main vertex buffer memory. That needs some more
4728 * investigation...
4732 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4735 ( (float *) dest_ptr)[0] = x;
4736 ( (float *) dest_ptr)[1] = y;
4737 ( (float *) dest_ptr)[2] = z;
4738 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4740 dest_ptr += 3 * sizeof(float);
4742 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4743 dest_ptr += sizeof(float);
4746 if(dest_conv) {
4747 float w = 1 / rhw;
4748 ( (float *) dest_conv)[0] = x * w;
4749 ( (float *) dest_conv)[1] = y * w;
4750 ( (float *) dest_conv)[2] = z * w;
4751 ( (float *) dest_conv)[3] = w;
4753 dest_conv += 3 * sizeof(float);
4755 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4756 dest_conv += sizeof(float);
4760 if (DestFVF & WINED3DFVF_PSIZE) {
4761 dest_ptr += sizeof(DWORD);
4762 if(dest_conv) dest_conv += sizeof(DWORD);
4764 if (DestFVF & WINED3DFVF_NORMAL) {
4765 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4766 const float *normal = (const float *)(element->data + i * element->stride);
4767 /* AFAIK this should go into the lighting information */
4768 FIXME("Didn't expect the destination to have a normal\n");
4769 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4770 if(dest_conv) {
4771 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4775 if (DestFVF & WINED3DFVF_DIFFUSE) {
4776 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4777 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4778 if(!color_d) {
4779 static BOOL warned = FALSE;
4781 if(!warned) {
4782 ERR("No diffuse color in source, but destination has one\n");
4783 warned = TRUE;
4786 *( (DWORD *) dest_ptr) = 0xffffffff;
4787 dest_ptr += sizeof(DWORD);
4789 if(dest_conv) {
4790 *( (DWORD *) dest_conv) = 0xffffffff;
4791 dest_conv += sizeof(DWORD);
4794 else {
4795 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4796 if(dest_conv) {
4797 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4798 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4799 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4800 dest_conv += sizeof(DWORD);
4805 if (DestFVF & WINED3DFVF_SPECULAR) {
4806 /* What's the color value in the feedback buffer? */
4807 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4808 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4809 if(!color_s) {
4810 static BOOL warned = FALSE;
4812 if(!warned) {
4813 ERR("No specular color in source, but destination has one\n");
4814 warned = TRUE;
4817 *( (DWORD *) dest_ptr) = 0xFF000000;
4818 dest_ptr += sizeof(DWORD);
4820 if(dest_conv) {
4821 *( (DWORD *) dest_conv) = 0xFF000000;
4822 dest_conv += sizeof(DWORD);
4825 else {
4826 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4827 if(dest_conv) {
4828 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4829 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4830 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4831 dest_conv += sizeof(DWORD);
4836 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4837 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4838 const float *tex_coord = (const float *)(element->data + i * element->stride);
4839 if(!tex_coord) {
4840 ERR("No source texture, but destination requests one\n");
4841 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4842 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4844 else {
4845 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4846 if(dest_conv) {
4847 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4853 if(dest_conv) {
4854 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4855 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4856 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4857 dwCount * get_flexible_vertex_size(DestFVF),
4858 dest_conv_addr));
4859 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4860 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4863 LEAVE_GL();
4865 return WINED3D_OK;
4867 #undef copy_and_next
4869 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4870 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 struct wined3d_stream_info stream_info;
4874 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4875 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4877 if(pVertexDecl) {
4878 ERR("Output vertex declaration not implemented yet\n");
4881 /* Need any context to write to the vbo. */
4882 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4884 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4885 * control the streamIsUP flag, thus restore it afterwards.
4887 This->stateBlock->streamIsUP = FALSE;
4888 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4889 This->stateBlock->streamIsUP = streamWasUP;
4891 if(vbo || SrcStartIndex) {
4892 unsigned int i;
4893 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4894 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4896 * Also get the start index in, but only loop over all elements if there's something to add at all.
4898 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4900 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4901 if (e->buffer_object)
4903 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4904 e->buffer_object = 0;
4905 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)vb->resource.allocatedMemory);
4906 ENTER_GL();
4907 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4908 vb->buffer_object = 0;
4909 LEAVE_GL();
4911 if (e->data) e->data += e->stride * SrcStartIndex;
4915 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4916 (struct wined3d_buffer *)pDestBuffer, Flags);
4919 /*****
4920 * Get / Set Texture Stage States
4921 * TODO: Verify against dx9 definitions
4922 *****/
4923 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4927 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4929 if (Stage >= MAX_TEXTURES) {
4930 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4931 return WINED3D_OK;
4934 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4935 This->updateStateBlock->textureState[Stage][Type] = Value;
4937 if (This->isRecordingState) {
4938 TRACE("Recording... not performing anything\n");
4939 return WINED3D_OK;
4942 /* Checked after the assignments to allow proper stateblock recording */
4943 if(oldValue == Value) {
4944 TRACE("App is setting the old value over, nothing to do\n");
4945 return WINED3D_OK;
4948 if(Stage > This->stateBlock->lowest_disabled_stage &&
4949 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4950 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4951 * Changes in other states are important on disabled stages too
4953 return WINED3D_OK;
4956 if(Type == WINED3DTSS_COLOROP) {
4957 unsigned int i;
4959 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4960 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4961 * they have to be disabled
4963 * The current stage is dirtified below.
4965 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4966 TRACE("Additionally dirtifying stage %u\n", i);
4967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4969 This->stateBlock->lowest_disabled_stage = Stage;
4970 TRACE("New lowest disabled: %u\n", Stage);
4971 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4972 /* Previously disabled stage enabled. Stages above it may need enabling
4973 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4974 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4976 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4979 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4980 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4981 break;
4983 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4986 This->stateBlock->lowest_disabled_stage = i;
4987 TRACE("New lowest disabled: %u\n", i);
4991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4993 return WINED3D_OK;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4999 *pValue = This->updateStateBlock->textureState[Stage][Type];
5000 return WINED3D_OK;
5003 /*****
5004 * Get / Set Texture
5005 *****/
5006 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 IWineD3DBaseTexture *oldTexture;
5010 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
5012 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5013 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5016 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5017 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5018 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5021 oldTexture = This->updateStateBlock->textures[Stage];
5023 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5024 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5026 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5027 return WINED3DERR_INVALIDCALL;
5030 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5031 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5033 This->updateStateBlock->changed.textures |= 1 << Stage;
5034 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5035 This->updateStateBlock->textures[Stage] = pTexture;
5037 /* Handle recording of state blocks */
5038 if (This->isRecordingState) {
5039 TRACE("Recording... not performing anything\n");
5040 return WINED3D_OK;
5043 if(oldTexture == pTexture) {
5044 TRACE("App is setting the same texture again, nothing to do\n");
5045 return WINED3D_OK;
5048 /** NOTE: MSDN says that setTexture increases the reference count,
5049 * and that the application must set the texture back to null (or have a leaky application),
5050 * This means we should pass the refcount up to the parent
5051 *******************************/
5052 if (NULL != This->updateStateBlock->textures[Stage]) {
5053 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5054 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5055 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5057 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5059 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5064 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5065 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5066 * so the COLOROP and ALPHAOP have to be dirtified.
5068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5071 if(bindCount == 1) {
5072 new->baseTexture.sampler = Stage;
5074 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5078 if (NULL != oldTexture) {
5079 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5080 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5082 IWineD3DBaseTexture_Release(oldTexture);
5083 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5088 if(bindCount && old->baseTexture.sampler == Stage) {
5089 int i;
5090 /* Have to do a search for the other sampler(s) where the texture is bound to
5091 * Shouldn't happen as long as apps bind a texture only to one stage
5093 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5094 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5095 if(This->updateStateBlock->textures[i] == oldTexture) {
5096 old->baseTexture.sampler = i;
5097 break;
5103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5105 return WINED3D_OK;
5108 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5113 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5114 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5117 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5118 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5119 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5122 *ppTexture=This->stateBlock->textures[Stage];
5123 if (*ppTexture)
5124 IWineD3DBaseTexture_AddRef(*ppTexture);
5126 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5128 return WINED3D_OK;
5131 /*****
5132 * Get Back Buffer
5133 *****/
5134 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5135 IWineD3DSurface **ppBackBuffer) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 IWineD3DSwapChain *swapChain;
5138 HRESULT hr;
5140 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5142 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5143 if (hr == WINED3D_OK) {
5144 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5145 IWineD3DSwapChain_Release(swapChain);
5146 } else {
5147 *ppBackBuffer = NULL;
5149 return hr;
5152 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5154 WARN("(%p) : stub, calling idirect3d for now\n", This);
5155 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5158 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5160 IWineD3DSwapChain *swapChain;
5161 HRESULT hr;
5163 if(iSwapChain > 0) {
5164 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5165 if (hr == WINED3D_OK) {
5166 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5167 IWineD3DSwapChain_Release(swapChain);
5168 } else {
5169 FIXME("(%p) Error getting display mode\n", This);
5171 } else {
5172 /* Don't read the real display mode,
5173 but return the stored mode instead. X11 can't change the color
5174 depth, and some apps are pretty angry if they SetDisplayMode from
5175 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5177 Also don't relay to the swapchain because with ddraw it's possible
5178 that there isn't a swapchain at all */
5179 pMode->Width = This->ddraw_width;
5180 pMode->Height = This->ddraw_height;
5181 pMode->Format = This->ddraw_format;
5182 pMode->RefreshRate = 0;
5183 hr = WINED3D_OK;
5186 return hr;
5189 /*****
5190 * Stateblock related functions
5191 *****/
5193 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5195 IWineD3DStateBlock *stateblock;
5196 HRESULT hr;
5198 TRACE("(%p)\n", This);
5200 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5202 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5203 if (FAILED(hr)) return hr;
5205 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5206 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5207 This->isRecordingState = TRUE;
5209 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5211 return WINED3D_OK;
5214 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5216 unsigned int i, j;
5217 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5219 if (!This->isRecordingState) {
5220 WARN("(%p) not recording! returning error\n", This);
5221 *ppStateBlock = NULL;
5222 return WINED3DERR_INVALIDCALL;
5225 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5227 DWORD map = object->changed.renderState[i];
5228 for (j = 0; map; map >>= 1, ++j)
5230 if (!(map & 1)) continue;
5232 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5236 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5238 DWORD map = object->changed.transform[i];
5239 for (j = 0; map; map >>= 1, ++j)
5241 if (!(map & 1)) continue;
5243 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5246 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5247 if(object->changed.vertexShaderConstantsF[i]) {
5248 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5249 object->num_contained_vs_consts_f++;
5252 for(i = 0; i < MAX_CONST_I; i++) {
5253 if (object->changed.vertexShaderConstantsI & (1 << i))
5255 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5256 object->num_contained_vs_consts_i++;
5259 for(i = 0; i < MAX_CONST_B; i++) {
5260 if (object->changed.vertexShaderConstantsB & (1 << i))
5262 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5263 object->num_contained_vs_consts_b++;
5266 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5268 if (object->changed.pixelShaderConstantsF[i])
5270 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5271 ++object->num_contained_ps_consts_f;
5274 for(i = 0; i < MAX_CONST_I; i++) {
5275 if (object->changed.pixelShaderConstantsI & (1 << i))
5277 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5278 object->num_contained_ps_consts_i++;
5281 for(i = 0; i < MAX_CONST_B; i++) {
5282 if (object->changed.pixelShaderConstantsB & (1 << i))
5284 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5285 object->num_contained_ps_consts_b++;
5288 for(i = 0; i < MAX_TEXTURES; i++) {
5289 DWORD map = object->changed.textureState[i];
5291 for(j = 0; map; map >>= 1, ++j)
5293 if (!(map & 1)) continue;
5295 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5296 object->contained_tss_states[object->num_contained_tss_states].state = j;
5297 ++object->num_contained_tss_states;
5300 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5301 DWORD map = object->changed.samplerState[i];
5303 for (j = 0; map; map >>= 1, ++j)
5305 if (!(map & 1)) continue;
5307 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5308 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5309 ++object->num_contained_sampler_states;
5313 *ppStateBlock = (IWineD3DStateBlock*) object;
5314 This->isRecordingState = FALSE;
5315 This->updateStateBlock = This->stateBlock;
5316 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5317 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5318 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5319 return WINED3D_OK;
5322 /*****
5323 * Scene related functions
5324 *****/
5325 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5326 /* At the moment we have no need for any functionality at the beginning
5327 of a scene */
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 TRACE("(%p)\n", This);
5331 if(This->inScene) {
5332 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5333 return WINED3DERR_INVALIDCALL;
5335 This->inScene = TRUE;
5336 return WINED3D_OK;
5339 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5341 TRACE("(%p)\n", This);
5343 if(!This->inScene) {
5344 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5345 return WINED3DERR_INVALIDCALL;
5348 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5349 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5350 glFlush();
5351 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5352 * fails
5355 This->inScene = FALSE;
5356 return WINED3D_OK;
5359 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5360 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5361 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5363 IWineD3DSwapChain *swapChain = NULL;
5364 int i;
5365 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5367 TRACE("(%p) Presenting the frame\n", This);
5369 for(i = 0 ; i < swapchains ; i ++) {
5371 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5372 TRACE("presentinng chain %d, %p\n", i, swapChain);
5373 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5374 IWineD3DSwapChain_Release(swapChain);
5377 return WINED3D_OK;
5380 /* Not called from the VTable (internal subroutine) */
5381 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5382 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5383 float Z, DWORD Stencil) {
5384 GLbitfield glMask = 0;
5385 unsigned int i;
5386 WINED3DRECT curRect;
5387 RECT vp_rect;
5388 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5389 UINT drawable_width, drawable_height;
5390 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5391 IWineD3DSwapChainImpl *swapchain = NULL;
5393 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5394 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5395 * for the cleared parts, and the untouched parts.
5397 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5398 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5399 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5400 * checking all this if the dest surface is in the drawable anyway.
5402 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5403 while(1) {
5404 if(vp->X != 0 || vp->Y != 0 ||
5405 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5406 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5407 break;
5409 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5410 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5411 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5412 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5413 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5414 break;
5416 if(Count > 0 && pRects && (
5417 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5418 pRects[0].x2 < target->currentDesc.Width ||
5419 pRects[0].y2 < target->currentDesc.Height)) {
5420 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5421 break;
5423 break;
5427 target->get_drawable_size(target, &drawable_width, &drawable_height);
5429 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5430 ENTER_GL();
5432 /* Only set the values up once, as they are not changing */
5433 if (Flags & WINED3DCLEAR_STENCIL) {
5434 glClearStencil(Stencil);
5435 checkGLcall("glClearStencil");
5436 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5437 glStencilMask(0xFFFFFFFF);
5440 if (Flags & WINED3DCLEAR_ZBUFFER) {
5441 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5442 glDepthMask(GL_TRUE);
5443 glClearDepth(Z);
5444 checkGLcall("glClearDepth");
5445 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5448 if (vp->X != 0 || vp->Y != 0 ||
5449 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5450 surface_load_ds_location(This->stencilBufferTarget, location);
5452 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5453 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5454 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5455 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5456 surface_load_ds_location(This->stencilBufferTarget, location);
5458 else if (Count > 0 && pRects && (
5459 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5460 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5461 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5462 surface_load_ds_location(This->stencilBufferTarget, location);
5466 if (Flags & WINED3DCLEAR_TARGET) {
5467 TRACE("Clearing screen with glClear to color %x\n", Color);
5468 glClearColor(D3DCOLOR_R(Color),
5469 D3DCOLOR_G(Color),
5470 D3DCOLOR_B(Color),
5471 D3DCOLOR_A(Color));
5472 checkGLcall("glClearColor");
5474 /* Clear ALL colors! */
5475 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5476 glMask = glMask | GL_COLOR_BUFFER_BIT;
5479 vp_rect.left = vp->X;
5480 vp_rect.top = vp->Y;
5481 vp_rect.right = vp->X + vp->Width;
5482 vp_rect.bottom = vp->Y + vp->Height;
5483 if (!(Count > 0 && pRects)) {
5484 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5485 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5487 if(This->render_offscreen) {
5488 glScissor(vp_rect.left, vp_rect.top,
5489 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5490 } else {
5491 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5492 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5494 checkGLcall("glScissor");
5495 glClear(glMask);
5496 checkGLcall("glClear");
5497 } else {
5498 /* Now process each rect in turn */
5499 for (i = 0; i < Count; i++) {
5500 /* Note gl uses lower left, width/height */
5501 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5502 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5503 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5505 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5506 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5507 curRect.x1, (target->currentDesc.Height - curRect.y2),
5508 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5510 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5511 * The rectangle is not cleared, no error is returned, but further rectanlges are
5512 * still cleared if they are valid
5514 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5515 TRACE("Rectangle with negative dimensions, ignoring\n");
5516 continue;
5519 if(This->render_offscreen) {
5520 glScissor(curRect.x1, curRect.y1,
5521 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5522 } else {
5523 glScissor(curRect.x1, drawable_height - curRect.y2,
5524 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5526 checkGLcall("glScissor");
5528 glClear(glMask);
5529 checkGLcall("glClear");
5533 /* Restore the old values (why..?) */
5534 if (Flags & WINED3DCLEAR_STENCIL) {
5535 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5537 if (Flags & WINED3DCLEAR_TARGET) {
5538 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5539 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5540 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5541 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5542 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5544 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5545 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5547 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5549 if (Flags & WINED3DCLEAR_ZBUFFER) {
5550 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5551 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5552 surface_modify_ds_location(This->stencilBufferTarget, location);
5555 LEAVE_GL();
5557 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5558 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5559 glFlush();
5561 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5564 return WINED3D_OK;
5567 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5568 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5570 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5572 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5573 Count, pRects, Flags, Color, Z, Stencil);
5575 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5576 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5577 /* TODO: What about depth stencil buffers without stencil bits? */
5578 return WINED3DERR_INVALIDCALL;
5581 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5584 /*****
5585 * Drawing functions
5586 *****/
5588 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5589 WINED3DPRIMITIVETYPE primitive_type)
5591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5595 This->updateStateBlock->changed.primitive_type = TRUE;
5596 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5599 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5600 WINED3DPRIMITIVETYPE *primitive_type)
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5604 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5606 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5608 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5611 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5617 if(!This->stateBlock->vertexDecl) {
5618 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5619 return WINED3DERR_INVALIDCALL;
5622 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5623 if(This->stateBlock->streamIsUP) {
5624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5625 This->stateBlock->streamIsUP = FALSE;
5628 if(This->stateBlock->loadBaseVertexIndex != 0) {
5629 This->stateBlock->loadBaseVertexIndex = 0;
5630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5632 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5633 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5634 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5635 return WINED3D_OK;
5638 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5639 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5642 UINT idxStride = 2;
5643 IWineD3DIndexBuffer *pIB;
5644 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5645 GLuint vbo;
5647 pIB = This->stateBlock->pIndexData;
5648 if (!pIB) {
5649 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5650 * without an index buffer set. (The first time at least...)
5651 * D3D8 simply dies, but I doubt it can do much harm to return
5652 * D3DERR_INVALIDCALL there as well. */
5653 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5654 return WINED3DERR_INVALIDCALL;
5657 if(!This->stateBlock->vertexDecl) {
5658 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5659 return WINED3DERR_INVALIDCALL;
5662 if(This->stateBlock->streamIsUP) {
5663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5664 This->stateBlock->streamIsUP = FALSE;
5666 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5668 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5669 This, minIndex, NumVertices, startIndex, index_count);
5671 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5672 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5673 idxStride = 2;
5674 } else {
5675 idxStride = 4;
5678 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5679 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5683 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5684 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5686 return WINED3D_OK;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5690 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5693 IWineD3DBuffer *vb;
5695 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5696 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5698 if(!This->stateBlock->vertexDecl) {
5699 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5700 return WINED3DERR_INVALIDCALL;
5703 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5704 vb = This->stateBlock->streamSource[0];
5705 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5706 if (vb) IWineD3DBuffer_Release(vb);
5707 This->stateBlock->streamOffset[0] = 0;
5708 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5709 This->stateBlock->streamIsUP = TRUE;
5710 This->stateBlock->loadBaseVertexIndex = 0;
5712 /* TODO: Only mark dirty if drawing from a different UP address */
5713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5715 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5716 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5718 /* MSDN specifies stream zero settings must be set to NULL */
5719 This->stateBlock->streamStride[0] = 0;
5720 This->stateBlock->streamSource[0] = NULL;
5722 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5723 * the new stream sources or use UP drawing again
5725 return WINED3D_OK;
5728 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5729 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5730 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5732 int idxStride;
5733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 IWineD3DBuffer *vb;
5735 IWineD3DIndexBuffer *ib;
5737 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5738 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5739 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5741 if(!This->stateBlock->vertexDecl) {
5742 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5743 return WINED3DERR_INVALIDCALL;
5746 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5747 idxStride = 2;
5748 } else {
5749 idxStride = 4;
5752 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5753 vb = This->stateBlock->streamSource[0];
5754 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5755 if (vb) IWineD3DBuffer_Release(vb);
5756 This->stateBlock->streamIsUP = TRUE;
5757 This->stateBlock->streamOffset[0] = 0;
5758 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5760 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5761 This->stateBlock->baseVertexIndex = 0;
5762 This->stateBlock->loadBaseVertexIndex = 0;
5763 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5767 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5768 idxStride, pIndexData, MinVertexIndex);
5770 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5771 This->stateBlock->streamSource[0] = NULL;
5772 This->stateBlock->streamStride[0] = 0;
5773 ib = This->stateBlock->pIndexData;
5774 if(ib) {
5775 IWineD3DIndexBuffer_Release(ib);
5776 This->stateBlock->pIndexData = NULL;
5778 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5779 * SetStreamSource to specify a vertex buffer
5782 return WINED3D_OK;
5785 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5786 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5790 /* Mark the state dirty until we have nicer tracking
5791 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5792 * that value.
5794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5796 This->stateBlock->baseVertexIndex = 0;
5797 This->up_strided = DrawPrimStrideData;
5798 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5799 This->up_strided = NULL;
5800 return WINED3D_OK;
5803 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5804 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5805 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5808 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5810 /* Mark the state dirty until we have nicer tracking
5811 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5812 * that value.
5814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5816 This->stateBlock->streamIsUP = TRUE;
5817 This->stateBlock->baseVertexIndex = 0;
5818 This->up_strided = DrawPrimStrideData;
5819 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5820 This->up_strided = NULL;
5821 return WINED3D_OK;
5824 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5825 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5826 * not callable by the app directly no parameter validation checks are needed here.
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5829 WINED3DLOCKED_BOX src;
5830 WINED3DLOCKED_BOX dst;
5831 HRESULT hr;
5832 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5834 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5835 * dirtification to improve loading performance.
5837 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5838 if(FAILED(hr)) return hr;
5839 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5840 if(FAILED(hr)) {
5841 IWineD3DVolume_UnlockBox(pSourceVolume);
5842 return hr;
5845 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5847 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5848 if(FAILED(hr)) {
5849 IWineD3DVolume_UnlockBox(pSourceVolume);
5850 } else {
5851 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5853 return hr;
5856 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5857 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5859 HRESULT hr = WINED3D_OK;
5860 WINED3DRESOURCETYPE sourceType;
5861 WINED3DRESOURCETYPE destinationType;
5862 int i ,levels;
5864 /* TODO: think about moving the code into IWineD3DBaseTexture */
5866 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5868 /* verify that the source and destination textures aren't NULL */
5869 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5870 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5871 This, pSourceTexture, pDestinationTexture);
5872 hr = WINED3DERR_INVALIDCALL;
5875 if (pSourceTexture == pDestinationTexture) {
5876 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5877 This, pSourceTexture, pDestinationTexture);
5878 hr = WINED3DERR_INVALIDCALL;
5880 /* Verify that the source and destination textures are the same type */
5881 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5882 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5884 if (sourceType != destinationType) {
5885 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5886 This);
5887 hr = WINED3DERR_INVALIDCALL;
5890 /* check that both textures have the identical numbers of levels */
5891 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5892 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5893 hr = WINED3DERR_INVALIDCALL;
5896 if (WINED3D_OK == hr) {
5897 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5899 /* Make sure that the destination texture is loaded */
5900 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5902 /* Update every surface level of the texture */
5903 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5905 switch (sourceType) {
5906 case WINED3DRTYPE_TEXTURE:
5908 IWineD3DSurface *srcSurface;
5909 IWineD3DSurface *destSurface;
5911 for (i = 0 ; i < levels ; ++i) {
5912 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5913 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5914 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5915 IWineD3DSurface_Release(srcSurface);
5916 IWineD3DSurface_Release(destSurface);
5917 if (WINED3D_OK != hr) {
5918 WARN("(%p) : Call to update surface failed\n", This);
5919 return hr;
5923 break;
5924 case WINED3DRTYPE_CUBETEXTURE:
5926 IWineD3DSurface *srcSurface;
5927 IWineD3DSurface *destSurface;
5928 WINED3DCUBEMAP_FACES faceType;
5930 for (i = 0 ; i < levels ; ++i) {
5931 /* Update each cube face */
5932 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5933 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5934 if (WINED3D_OK != hr) {
5935 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5936 } else {
5937 TRACE("Got srcSurface %p\n", srcSurface);
5939 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5940 if (WINED3D_OK != hr) {
5941 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5942 } else {
5943 TRACE("Got desrSurface %p\n", destSurface);
5945 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5946 IWineD3DSurface_Release(srcSurface);
5947 IWineD3DSurface_Release(destSurface);
5948 if (WINED3D_OK != hr) {
5949 WARN("(%p) : Call to update surface failed\n", This);
5950 return hr;
5955 break;
5957 case WINED3DRTYPE_VOLUMETEXTURE:
5959 IWineD3DVolume *srcVolume = NULL;
5960 IWineD3DVolume *destVolume = NULL;
5962 for (i = 0 ; i < levels ; ++i) {
5963 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5964 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5965 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5966 IWineD3DVolume_Release(srcVolume);
5967 IWineD3DVolume_Release(destVolume);
5968 if (WINED3D_OK != hr) {
5969 WARN("(%p) : Call to update volume failed\n", This);
5970 return hr;
5974 break;
5976 default:
5977 FIXME("(%p) : Unsupported source and destination type\n", This);
5978 hr = WINED3DERR_INVALIDCALL;
5982 return hr;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5986 IWineD3DSwapChain *swapChain;
5987 HRESULT hr;
5988 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5989 if(hr == WINED3D_OK) {
5990 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5991 IWineD3DSwapChain_Release(swapChain);
5993 return hr;
5996 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5998 IWineD3DBaseTextureImpl *texture;
5999 DWORD i;
6001 TRACE("(%p) : %p\n", This, pNumPasses);
6003 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6004 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
6005 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6006 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6008 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
6009 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6010 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6013 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
6014 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6016 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6017 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6018 return E_FAIL;
6020 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6021 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6022 return E_FAIL;
6024 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6025 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6026 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6027 return E_FAIL;
6031 /* return a sensible default */
6032 *pNumPasses = 1;
6034 TRACE("returning D3D_OK\n");
6035 return WINED3D_OK;
6038 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6040 int i;
6042 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6043 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6044 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6045 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6047 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6052 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054 int j;
6055 UINT NewSize;
6056 PALETTEENTRY **palettes;
6058 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6060 if (PaletteNumber >= MAX_PALETTES) {
6061 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6062 return WINED3DERR_INVALIDCALL;
6065 if (PaletteNumber >= This->NumberOfPalettes) {
6066 NewSize = This->NumberOfPalettes;
6067 do {
6068 NewSize *= 2;
6069 } while(PaletteNumber >= NewSize);
6070 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6071 if (!palettes) {
6072 ERR("Out of memory!\n");
6073 return E_OUTOFMEMORY;
6075 This->palettes = palettes;
6076 This->NumberOfPalettes = NewSize;
6079 if (!This->palettes[PaletteNumber]) {
6080 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6081 if (!This->palettes[PaletteNumber]) {
6082 ERR("Out of memory!\n");
6083 return E_OUTOFMEMORY;
6087 for (j = 0; j < 256; ++j) {
6088 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6089 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6090 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6091 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6093 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6094 TRACE("(%p) : returning\n", This);
6095 return WINED3D_OK;
6098 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6100 int j;
6101 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6102 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6103 /* What happens in such situation isn't documented; Native seems to silently abort
6104 on such conditions. Return Invalid Call. */
6105 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6106 return WINED3DERR_INVALIDCALL;
6108 for (j = 0; j < 256; ++j) {
6109 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6110 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6111 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6112 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6114 TRACE("(%p) : returning\n", This);
6115 return WINED3D_OK;
6118 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6121 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6122 (tested with reference rasterizer). Return Invalid Call. */
6123 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6124 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6125 return WINED3DERR_INVALIDCALL;
6127 /*TODO: stateblocks */
6128 if (This->currentPalette != PaletteNumber) {
6129 This->currentPalette = PaletteNumber;
6130 dirtify_p8_texture_samplers(This);
6132 TRACE("(%p) : returning\n", This);
6133 return WINED3D_OK;
6136 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6138 if (PaletteNumber == NULL) {
6139 WARN("(%p) : returning Invalid Call\n", This);
6140 return WINED3DERR_INVALIDCALL;
6142 /*TODO: stateblocks */
6143 *PaletteNumber = This->currentPalette;
6144 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6145 return WINED3D_OK;
6148 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6150 static BOOL warned;
6151 if (!warned)
6153 FIXME("(%p) : stub\n", This);
6154 warned = TRUE;
6157 This->softwareVertexProcessing = bSoftware;
6158 return WINED3D_OK;
6162 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6164 static BOOL warned;
6165 if (!warned)
6167 FIXME("(%p) : stub\n", This);
6168 warned = TRUE;
6170 return This->softwareVertexProcessing;
6174 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6176 IWineD3DSwapChain *swapChain;
6177 HRESULT hr;
6179 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6181 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6182 if(hr == WINED3D_OK){
6183 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6184 IWineD3DSwapChain_Release(swapChain);
6185 }else{
6186 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6188 return hr;
6192 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 static BOOL warned;
6195 if(nSegments != 0.0f) {
6196 if (!warned)
6198 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6199 warned = TRUE;
6202 return WINED3D_OK;
6205 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6207 static BOOL warned;
6208 if (!warned)
6210 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6211 warned = TRUE;
6213 return 0.0f;
6216 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6218 /** TODO: remove casts to IWineD3DSurfaceImpl
6219 * NOTE: move code to surface to accomplish this
6220 ****************************************/
6221 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6222 int srcWidth, srcHeight;
6223 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6224 WINED3DFORMAT destFormat, srcFormat;
6225 UINT destSize;
6226 int srcLeft, destLeft, destTop;
6227 WINED3DPOOL srcPool, destPool;
6228 int offset = 0;
6229 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6230 glDescriptor *glDescription = NULL;
6231 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6232 GLenum dummy;
6233 int sampler;
6234 int bpp;
6235 CONVERT_TYPES convert = NO_CONVERSION;
6237 WINED3DSURFACE_DESC winedesc;
6239 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6240 memset(&winedesc, 0, sizeof(winedesc));
6241 winedesc.Width = &srcSurfaceWidth;
6242 winedesc.Height = &srcSurfaceHeight;
6243 winedesc.Pool = &srcPool;
6244 winedesc.Format = &srcFormat;
6246 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6248 winedesc.Width = &destSurfaceWidth;
6249 winedesc.Height = &destSurfaceHeight;
6250 winedesc.Pool = &destPool;
6251 winedesc.Format = &destFormat;
6252 winedesc.Size = &destSize;
6254 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6256 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6257 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6258 return WINED3DERR_INVALIDCALL;
6261 /* This call loads the opengl surface directly, instead of copying the surface to the
6262 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6263 * copy in sysmem and use regular surface loading.
6265 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6266 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6267 if(convert != NO_CONVERSION) {
6268 return IWineD3DSurface_BltFast(pDestinationSurface,
6269 pDestPoint ? pDestPoint->x : 0,
6270 pDestPoint ? pDestPoint->y : 0,
6271 pSourceSurface, pSourceRect, 0);
6274 if (destFormat == WINED3DFMT_UNKNOWN) {
6275 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6276 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6278 /* Get the update surface description */
6279 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6282 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6284 ENTER_GL();
6285 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6286 checkGLcall("glActiveTextureARB");
6287 LEAVE_GL();
6289 /* Make sure the surface is loaded and up to date */
6290 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6291 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6293 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6295 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6296 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6298 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6299 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6300 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6301 srcLeft = pSourceRect ? pSourceRect->left : 0;
6302 destLeft = pDestPoint ? pDestPoint->x : 0;
6303 destTop = pDestPoint ? pDestPoint->y : 0;
6306 /* This function doesn't support compressed textures
6307 the pitch is just bytesPerPixel * width */
6308 if(srcWidth != srcSurfaceWidth || srcLeft ){
6309 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6310 offset += srcLeft * src_format_desc->byte_count;
6311 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6313 /* TODO DXT formats */
6315 if(pSourceRect != NULL && pSourceRect->top != 0){
6316 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6318 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6319 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6320 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6322 /* Sanity check */
6323 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6325 /* need to lock the surface to get the data */
6326 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6329 ENTER_GL();
6331 /* TODO: Cube and volume support */
6332 if(rowoffset != 0){
6333 /* not a whole row so we have to do it a line at a time */
6334 int j;
6336 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6337 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6339 for (j = destTop; j < (srcHeight + destTop); ++j)
6341 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6342 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6343 data += rowoffset;
6346 } else { /* Full width, so just write out the whole texture */
6347 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6349 if (WINED3DFMT_DXT1 == destFormat ||
6350 WINED3DFMT_DXT2 == destFormat ||
6351 WINED3DFMT_DXT3 == destFormat ||
6352 WINED3DFMT_DXT4 == destFormat ||
6353 WINED3DFMT_DXT5 == destFormat) {
6354 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6355 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6356 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6357 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6358 } if (destFormat != srcFormat) {
6359 FIXME("Updating mixed format compressed texture is not curretly support\n");
6360 } else {
6361 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6362 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6364 } else {
6365 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6369 } else {
6370 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6371 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6374 checkGLcall("glTexSubImage2D");
6376 LEAVE_GL();
6378 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6379 sampler = This->rev_tex_unit_map[0];
6380 if (sampler != -1) {
6381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6384 return WINED3D_OK;
6387 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6389 struct WineD3DRectPatch *patch;
6390 GLenum old_primitive_type;
6391 unsigned int i;
6392 struct list *e;
6393 BOOL found;
6394 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6396 if(!(Handle || pRectPatchInfo)) {
6397 /* TODO: Write a test for the return value, thus the FIXME */
6398 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6399 return WINED3DERR_INVALIDCALL;
6402 if(Handle) {
6403 i = PATCHMAP_HASHFUNC(Handle);
6404 found = FALSE;
6405 LIST_FOR_EACH(e, &This->patches[i]) {
6406 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6407 if(patch->Handle == Handle) {
6408 found = TRUE;
6409 break;
6413 if(!found) {
6414 TRACE("Patch does not exist. Creating a new one\n");
6415 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6416 patch->Handle = Handle;
6417 list_add_head(&This->patches[i], &patch->entry);
6418 } else {
6419 TRACE("Found existing patch %p\n", patch);
6421 } else {
6422 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6423 * attributes we have to tesselate, read back, and draw. This needs a patch
6424 * management structure instance. Create one.
6426 * A possible improvement is to check if a vertex shader is used, and if not directly
6427 * draw the patch.
6429 FIXME("Drawing an uncached patch. This is slow\n");
6430 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6433 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6434 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6435 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6436 HRESULT hr;
6437 TRACE("Tesselation density or patch info changed, retesselating\n");
6439 if(pRectPatchInfo) {
6440 patch->RectPatchInfo = *pRectPatchInfo;
6442 patch->numSegs[0] = pNumSegs[0];
6443 patch->numSegs[1] = pNumSegs[1];
6444 patch->numSegs[2] = pNumSegs[2];
6445 patch->numSegs[3] = pNumSegs[3];
6447 hr = tesselate_rectpatch(This, patch);
6448 if(FAILED(hr)) {
6449 WARN("Patch tesselation failed\n");
6451 /* Do not release the handle to store the params of the patch */
6452 if(!Handle) {
6453 HeapFree(GetProcessHeap(), 0, patch);
6455 return hr;
6459 This->currentPatch = patch;
6460 old_primitive_type = This->stateBlock->gl_primitive_type;
6461 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6462 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6463 This->stateBlock->gl_primitive_type = old_primitive_type;
6464 This->currentPatch = NULL;
6466 /* Destroy uncached patches */
6467 if(!Handle) {
6468 HeapFree(GetProcessHeap(), 0, patch->mem);
6469 HeapFree(GetProcessHeap(), 0, patch);
6471 return WINED3D_OK;
6474 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6476 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6477 FIXME("(%p) : Stub\n", This);
6478 return WINED3D_OK;
6481 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6483 int i;
6484 struct WineD3DRectPatch *patch;
6485 struct list *e;
6486 TRACE("(%p) Handle(%d)\n", This, Handle);
6488 i = PATCHMAP_HASHFUNC(Handle);
6489 LIST_FOR_EACH(e, &This->patches[i]) {
6490 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6491 if(patch->Handle == Handle) {
6492 TRACE("Deleting patch %p\n", patch);
6493 list_remove(&patch->entry);
6494 HeapFree(GetProcessHeap(), 0, patch->mem);
6495 HeapFree(GetProcessHeap(), 0, patch);
6496 return WINED3D_OK;
6500 /* TODO: Write a test for the return value */
6501 FIXME("Attempt to destroy nonexistent patch\n");
6502 return WINED3DERR_INVALIDCALL;
6505 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6506 HRESULT hr;
6507 IWineD3DSwapChain *swapchain;
6509 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6510 if (SUCCEEDED(hr)) {
6511 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6512 return swapchain;
6515 return NULL;
6518 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6519 const WINED3DRECT *rect, const float color[4])
6521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6522 IWineD3DSwapChain *swapchain;
6524 swapchain = get_swapchain(surface);
6525 if (swapchain) {
6526 GLenum buffer;
6528 TRACE("Surface %p is onscreen\n", surface);
6530 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6531 ENTER_GL();
6532 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6533 buffer = surface_get_gl_buffer(surface, swapchain);
6534 glDrawBuffer(buffer);
6535 checkGLcall("glDrawBuffer()");
6536 } else {
6537 TRACE("Surface %p is offscreen\n", surface);
6539 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6540 ENTER_GL();
6541 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6542 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6543 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6544 checkGLcall("glFramebufferRenderbufferEXT");
6547 if (rect) {
6548 glEnable(GL_SCISSOR_TEST);
6549 if(!swapchain) {
6550 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6551 } else {
6552 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6553 rect->x2 - rect->x1, rect->y2 - rect->y1);
6555 checkGLcall("glScissor");
6556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6557 } else {
6558 glDisable(GL_SCISSOR_TEST);
6560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6562 glDisable(GL_BLEND);
6563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6565 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6568 glClearColor(color[0], color[1], color[2], color[3]);
6569 glClear(GL_COLOR_BUFFER_BIT);
6570 checkGLcall("glClear");
6572 if (This->activeContext->current_fbo) {
6573 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6574 } else {
6575 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6576 checkGLcall("glBindFramebuffer()");
6579 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6580 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6581 glDrawBuffer(GL_BACK);
6582 checkGLcall("glDrawBuffer()");
6585 LEAVE_GL();
6588 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6589 unsigned int r, g, b, a;
6590 DWORD ret;
6592 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6593 destfmt == WINED3DFMT_R8G8B8)
6594 return color;
6596 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6598 a = (color & 0xff000000) >> 24;
6599 r = (color & 0x00ff0000) >> 16;
6600 g = (color & 0x0000ff00) >> 8;
6601 b = (color & 0x000000ff) >> 0;
6603 switch(destfmt)
6605 case WINED3DFMT_R5G6B5:
6606 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6607 r = (r * 32) / 256;
6608 g = (g * 64) / 256;
6609 b = (b * 32) / 256;
6610 ret = r << 11;
6611 ret |= g << 5;
6612 ret |= b;
6613 TRACE("Returning %08x\n", ret);
6614 return ret;
6616 case WINED3DFMT_X1R5G5B5:
6617 case WINED3DFMT_A1R5G5B5:
6618 a = (a * 2) / 256;
6619 r = (r * 32) / 256;
6620 g = (g * 32) / 256;
6621 b = (b * 32) / 256;
6622 ret = a << 15;
6623 ret |= r << 10;
6624 ret |= g << 5;
6625 ret |= b << 0;
6626 TRACE("Returning %08x\n", ret);
6627 return ret;
6629 case WINED3DFMT_A8_UNORM:
6630 TRACE("Returning %08x\n", a);
6631 return a;
6633 case WINED3DFMT_X4R4G4B4:
6634 case WINED3DFMT_A4R4G4B4:
6635 a = (a * 16) / 256;
6636 r = (r * 16) / 256;
6637 g = (g * 16) / 256;
6638 b = (b * 16) / 256;
6639 ret = a << 12;
6640 ret |= r << 8;
6641 ret |= g << 4;
6642 ret |= b << 0;
6643 TRACE("Returning %08x\n", ret);
6644 return ret;
6646 case WINED3DFMT_R3G3B2:
6647 r = (r * 8) / 256;
6648 g = (g * 8) / 256;
6649 b = (b * 4) / 256;
6650 ret = r << 5;
6651 ret |= g << 2;
6652 ret |= b << 0;
6653 TRACE("Returning %08x\n", ret);
6654 return ret;
6656 case WINED3DFMT_X8B8G8R8:
6657 case WINED3DFMT_R8G8B8A8_UNORM:
6658 ret = a << 24;
6659 ret |= b << 16;
6660 ret |= g << 8;
6661 ret |= r << 0;
6662 TRACE("Returning %08x\n", ret);
6663 return ret;
6665 case WINED3DFMT_A2R10G10B10:
6666 a = (a * 4) / 256;
6667 r = (r * 1024) / 256;
6668 g = (g * 1024) / 256;
6669 b = (b * 1024) / 256;
6670 ret = a << 30;
6671 ret |= r << 20;
6672 ret |= g << 10;
6673 ret |= b << 0;
6674 TRACE("Returning %08x\n", ret);
6675 return ret;
6677 case WINED3DFMT_R10G10B10A2_UNORM:
6678 a = (a * 4) / 256;
6679 r = (r * 1024) / 256;
6680 g = (g * 1024) / 256;
6681 b = (b * 1024) / 256;
6682 ret = a << 30;
6683 ret |= b << 20;
6684 ret |= g << 10;
6685 ret |= r << 0;
6686 TRACE("Returning %08x\n", ret);
6687 return ret;
6689 default:
6690 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6691 return 0;
6695 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6697 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6698 WINEDDBLTFX BltFx;
6699 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6701 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6702 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6703 return WINED3DERR_INVALIDCALL;
6706 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6707 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6708 color_fill_fbo(iface, pSurface, pRect, c);
6709 return WINED3D_OK;
6710 } else {
6711 /* Just forward this to the DirectDraw blitting engine */
6712 memset(&BltFx, 0, sizeof(BltFx));
6713 BltFx.dwSize = sizeof(BltFx);
6714 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6715 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6716 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6720 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6721 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6723 IWineD3DResource *resource;
6724 IWineD3DSurface *surface;
6725 HRESULT hr;
6727 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6728 if (FAILED(hr))
6730 ERR("Failed to get resource, hr %#x\n", hr);
6731 return;
6734 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6736 FIXME("Only supported on surface resources\n");
6737 IWineD3DResource_Release(resource);
6738 return;
6741 surface = (IWineD3DSurface *)resource;
6743 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6745 color_fill_fbo(iface, surface, NULL, color);
6747 else
6749 WINEDDBLTFX BltFx;
6750 WINED3DCOLOR c;
6752 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6754 c = ((DWORD)(color[2] * 255.0));
6755 c |= ((DWORD)(color[1] * 255.0)) << 8;
6756 c |= ((DWORD)(color[0] * 255.0)) << 16;
6757 c |= ((DWORD)(color[3] * 255.0)) << 24;
6759 /* Just forward this to the DirectDraw blitting engine */
6760 memset(&BltFx, 0, sizeof(BltFx));
6761 BltFx.dwSize = sizeof(BltFx);
6762 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6763 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6764 if (FAILED(hr))
6766 ERR("Blt failed, hr %#x\n", hr);
6770 IWineD3DResource_Release(resource);
6773 /* rendertarget and depth stencil functions */
6774 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6777 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6778 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6779 return WINED3DERR_INVALIDCALL;
6782 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6783 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6784 /* Note inc ref on returned surface */
6785 if(*ppRenderTarget != NULL)
6786 IWineD3DSurface_AddRef(*ppRenderTarget);
6787 return WINED3D_OK;
6790 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6792 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6793 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6794 IWineD3DSwapChainImpl *Swapchain;
6795 HRESULT hr;
6797 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6799 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6800 if(hr != WINED3D_OK) {
6801 ERR("Can't get the swapchain\n");
6802 return hr;
6805 /* Make sure to release the swapchain */
6806 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6808 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6809 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6810 return WINED3DERR_INVALIDCALL;
6812 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6813 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6814 return WINED3DERR_INVALIDCALL;
6817 if(Swapchain->frontBuffer != Front) {
6818 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6820 if(Swapchain->frontBuffer)
6822 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6823 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6825 Swapchain->frontBuffer = Front;
6827 if(Swapchain->frontBuffer) {
6828 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6829 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6833 if(Back && !Swapchain->backBuffer) {
6834 /* We need memory for the back buffer array - only one back buffer this way */
6835 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6836 if(!Swapchain->backBuffer) {
6837 ERR("Out of memory\n");
6838 return E_OUTOFMEMORY;
6842 if(Swapchain->backBuffer[0] != Back) {
6843 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6845 /* What to do about the context here in the case of multithreading? Not sure.
6846 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6848 ENTER_GL();
6849 if(!Swapchain->backBuffer[0]) {
6850 /* GL was told to draw to the front buffer at creation,
6851 * undo that
6853 glDrawBuffer(GL_BACK);
6854 checkGLcall("glDrawBuffer(GL_BACK)");
6855 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6856 Swapchain->presentParms.BackBufferCount = 1;
6857 } else if (!Back) {
6858 /* That makes problems - disable for now */
6859 /* glDrawBuffer(GL_FRONT); */
6860 checkGLcall("glDrawBuffer(GL_FRONT)");
6861 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6862 Swapchain->presentParms.BackBufferCount = 0;
6864 LEAVE_GL();
6866 if(Swapchain->backBuffer[0])
6868 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6869 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6871 Swapchain->backBuffer[0] = Back;
6873 if(Swapchain->backBuffer[0]) {
6874 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6875 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6876 } else {
6877 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6878 Swapchain->backBuffer = NULL;
6883 return WINED3D_OK;
6886 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6888 *ppZStencilSurface = This->stencilBufferTarget;
6889 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6891 if(*ppZStencilSurface != NULL) {
6892 /* Note inc ref on returned surface */
6893 IWineD3DSurface_AddRef(*ppZStencilSurface);
6894 return WINED3D_OK;
6895 } else {
6896 return WINED3DERR_NOTFOUND;
6900 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6901 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6904 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6905 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6906 GLenum gl_filter;
6907 POINT offset = {0, 0};
6909 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6910 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6911 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6912 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6914 switch (filter) {
6915 case WINED3DTEXF_LINEAR:
6916 gl_filter = GL_LINEAR;
6917 break;
6919 default:
6920 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6921 case WINED3DTEXF_NONE:
6922 case WINED3DTEXF_POINT:
6923 gl_filter = GL_NEAREST;
6924 break;
6927 /* Attach src surface to src fbo */
6928 src_swapchain = get_swapchain(src_surface);
6929 if (src_swapchain) {
6930 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6932 TRACE("Source surface %p is onscreen\n", src_surface);
6933 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6934 /* Make sure the drawable is up to date. In the offscreen case
6935 * attach_surface_fbo() implicitly takes care of this. */
6936 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6938 if(buffer == GL_FRONT) {
6939 RECT windowsize;
6940 UINT h;
6941 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6942 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6943 h = windowsize.bottom - windowsize.top;
6944 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6945 src_rect->y1 = offset.y + h - src_rect->y1;
6946 src_rect->y2 = offset.y + h - src_rect->y2;
6947 } else {
6948 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6949 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6952 ENTER_GL();
6953 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6954 glReadBuffer(buffer);
6955 checkGLcall("glReadBuffer()");
6956 } else {
6957 TRACE("Source surface %p is offscreen\n", src_surface);
6958 ENTER_GL();
6959 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6960 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6961 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6962 checkGLcall("glReadBuffer()");
6963 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6964 checkGLcall("glFramebufferRenderbufferEXT");
6966 LEAVE_GL();
6968 /* Attach dst surface to dst fbo */
6969 dst_swapchain = get_swapchain(dst_surface);
6970 if (dst_swapchain) {
6971 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6973 TRACE("Destination surface %p is onscreen\n", dst_surface);
6974 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6975 /* Make sure the drawable is up to date. In the offscreen case
6976 * attach_surface_fbo() implicitly takes care of this. */
6977 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6979 if(buffer == GL_FRONT) {
6980 RECT windowsize;
6981 UINT h;
6982 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6983 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6984 h = windowsize.bottom - windowsize.top;
6985 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6986 dst_rect->y1 = offset.y + h - dst_rect->y1;
6987 dst_rect->y2 = offset.y + h - dst_rect->y2;
6988 } else {
6989 /* Screen coords = window coords, surface height = window height */
6990 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6991 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6994 ENTER_GL();
6995 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6996 glDrawBuffer(buffer);
6997 checkGLcall("glDrawBuffer()");
6998 } else {
6999 TRACE("Destination surface %p is offscreen\n", dst_surface);
7001 /* No src or dst swapchain? Make sure some context is active(multithreading) */
7002 if(!src_swapchain) {
7003 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7006 ENTER_GL();
7007 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
7008 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
7009 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
7010 checkGLcall("glDrawBuffer()");
7011 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7012 checkGLcall("glFramebufferRenderbufferEXT");
7014 glDisable(GL_SCISSOR_TEST);
7015 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7017 if (flip) {
7018 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7019 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7020 checkGLcall("glBlitFramebuffer()");
7021 } else {
7022 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7023 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7024 checkGLcall("glBlitFramebuffer()");
7027 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7029 if (This->activeContext->current_fbo) {
7030 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7031 } else {
7032 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7033 checkGLcall("glBindFramebuffer()");
7036 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7037 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7038 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7039 glDrawBuffer(GL_BACK);
7040 checkGLcall("glDrawBuffer()");
7042 LEAVE_GL();
7045 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7047 WINED3DVIEWPORT viewport;
7049 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7051 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7052 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7053 This, RenderTargetIndex, GL_LIMITS(buffers));
7054 return WINED3DERR_INVALIDCALL;
7057 /* MSDN says that null disables the render target
7058 but a device must always be associated with a render target
7059 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7061 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7062 FIXME("Trying to set render target 0 to NULL\n");
7063 return WINED3DERR_INVALIDCALL;
7065 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7066 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);
7067 return WINED3DERR_INVALIDCALL;
7070 /* If we are trying to set what we already have, don't bother */
7071 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7072 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7073 return WINED3D_OK;
7075 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7076 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7077 This->render_targets[RenderTargetIndex] = pRenderTarget;
7079 /* Render target 0 is special */
7080 if(RenderTargetIndex == 0) {
7081 /* Finally, reset the viewport as the MSDN states. */
7082 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7083 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7084 viewport.X = 0;
7085 viewport.Y = 0;
7086 viewport.MaxZ = 1.0f;
7087 viewport.MinZ = 0.0f;
7088 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7089 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7090 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7094 return WINED3D_OK;
7097 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7099 HRESULT hr = WINED3D_OK;
7100 IWineD3DSurface *tmp;
7102 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7104 if (pNewZStencil == This->stencilBufferTarget) {
7105 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7106 } else {
7107 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7108 * depending on the renter target implementation being used.
7109 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7110 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7111 * stencil buffer and incur an extra memory overhead
7112 ******************************************************/
7114 if (This->stencilBufferTarget) {
7115 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7116 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7117 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7118 } else {
7119 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7120 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7121 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7125 tmp = This->stencilBufferTarget;
7126 This->stencilBufferTarget = pNewZStencil;
7127 /* should we be calling the parent or the wined3d surface? */
7128 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7129 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7130 hr = WINED3D_OK;
7132 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7133 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7140 return hr;
7143 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7144 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7146 /* TODO: the use of Impl is deprecated. */
7147 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7148 WINED3DLOCKED_RECT lockedRect;
7150 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7152 /* some basic validation checks */
7153 if(This->cursorTexture) {
7154 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7155 ENTER_GL();
7156 glDeleteTextures(1, &This->cursorTexture);
7157 LEAVE_GL();
7158 This->cursorTexture = 0;
7161 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7162 This->haveHardwareCursor = TRUE;
7163 else
7164 This->haveHardwareCursor = FALSE;
7166 if(pCursorBitmap) {
7167 WINED3DLOCKED_RECT rect;
7169 /* MSDN: Cursor must be A8R8G8B8 */
7170 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7172 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7173 return WINED3DERR_INVALIDCALL;
7176 /* MSDN: Cursor must be smaller than the display mode */
7177 if(pSur->currentDesc.Width > This->ddraw_width ||
7178 pSur->currentDesc.Height > This->ddraw_height) {
7179 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);
7180 return WINED3DERR_INVALIDCALL;
7183 if (!This->haveHardwareCursor) {
7184 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7186 /* Do not store the surface's pointer because the application may
7187 * release it after setting the cursor image. Windows doesn't
7188 * addref the set surface, so we can't do this either without
7189 * creating circular refcount dependencies. Copy out the gl texture
7190 * instead.
7192 This->cursorWidth = pSur->currentDesc.Width;
7193 This->cursorHeight = pSur->currentDesc.Height;
7194 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7196 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7197 char *mem, *bits = rect.pBits;
7198 GLint intfmt = glDesc->glInternal;
7199 GLint format = glDesc->glFormat;
7200 GLint type = glDesc->glType;
7201 INT height = This->cursorHeight;
7202 INT width = This->cursorWidth;
7203 INT bpp = glDesc->byte_count;
7204 INT i, sampler;
7206 /* Reformat the texture memory (pitch and width can be
7207 * different) */
7208 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7209 for(i = 0; i < height; i++)
7210 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7211 IWineD3DSurface_UnlockRect(pCursorBitmap);
7212 ENTER_GL();
7214 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7215 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7216 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7219 /* Make sure that a proper texture unit is selected */
7220 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7221 checkGLcall("glActiveTextureARB");
7222 sampler = This->rev_tex_unit_map[0];
7223 if (sampler != -1) {
7224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7226 /* Create a new cursor texture */
7227 glGenTextures(1, &This->cursorTexture);
7228 checkGLcall("glGenTextures");
7229 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7230 checkGLcall("glBindTexture");
7231 /* Copy the bitmap memory into the cursor texture */
7232 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7233 HeapFree(GetProcessHeap(), 0, mem);
7234 checkGLcall("glTexImage2D");
7236 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7237 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7238 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7241 LEAVE_GL();
7243 else
7245 FIXME("A cursor texture was not returned.\n");
7246 This->cursorTexture = 0;
7249 else
7251 /* Draw a hardware cursor */
7252 ICONINFO cursorInfo;
7253 HCURSOR cursor;
7254 /* Create and clear maskBits because it is not needed for
7255 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7256 * chunks. */
7257 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7258 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7259 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7260 WINED3DLOCK_NO_DIRTY_UPDATE |
7261 WINED3DLOCK_READONLY
7263 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7264 pSur->currentDesc.Height);
7266 cursorInfo.fIcon = FALSE;
7267 cursorInfo.xHotspot = XHotSpot;
7268 cursorInfo.yHotspot = YHotSpot;
7269 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7270 pSur->currentDesc.Height, 1,
7271 1, &maskBits);
7272 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7273 pSur->currentDesc.Height, 1,
7274 32, lockedRect.pBits);
7275 IWineD3DSurface_UnlockRect(pCursorBitmap);
7276 /* Create our cursor and clean up. */
7277 cursor = CreateIconIndirect(&cursorInfo);
7278 SetCursor(cursor);
7279 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7280 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7281 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7282 This->hardwareCursor = cursor;
7283 HeapFree(GetProcessHeap(), 0, maskBits);
7287 This->xHotSpot = XHotSpot;
7288 This->yHotSpot = YHotSpot;
7289 return WINED3D_OK;
7292 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7294 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7296 This->xScreenSpace = XScreenSpace;
7297 This->yScreenSpace = YScreenSpace;
7299 return;
7303 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7305 BOOL oldVisible = This->bCursorVisible;
7306 POINT pt;
7308 TRACE("(%p) : visible(%d)\n", This, bShow);
7311 * When ShowCursor is first called it should make the cursor appear at the OS's last
7312 * known cursor position. Because of this, some applications just repetitively call
7313 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7315 GetCursorPos(&pt);
7316 This->xScreenSpace = pt.x;
7317 This->yScreenSpace = pt.y;
7319 if (This->haveHardwareCursor) {
7320 This->bCursorVisible = bShow;
7321 if (bShow)
7322 SetCursor(This->hardwareCursor);
7323 else
7324 SetCursor(NULL);
7326 else
7328 if (This->cursorTexture)
7329 This->bCursorVisible = bShow;
7332 return oldVisible;
7335 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7337 IWineD3DResourceImpl *resource;
7338 TRACE("(%p) : state (%u)\n", This, This->state);
7340 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7341 switch (This->state) {
7342 case WINED3D_OK:
7343 return WINED3D_OK;
7344 case WINED3DERR_DEVICELOST:
7346 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7347 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7348 return WINED3DERR_DEVICENOTRESET;
7350 return WINED3DERR_DEVICELOST;
7352 case WINED3DERR_DRIVERINTERNALERROR:
7353 return WINED3DERR_DRIVERINTERNALERROR;
7356 /* Unknown state */
7357 return WINED3DERR_DRIVERINTERNALERROR;
7361 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7363 /** FIXME: Resource tracking needs to be done,
7364 * The closes we can do to this is set the priorities of all managed textures low
7365 * and then reset them.
7366 ***********************************************************/
7367 FIXME("(%p) : stub\n", This);
7368 return WINED3D_OK;
7371 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7373 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7375 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7376 if(surface->Flags & SFLAG_DIBSECTION) {
7377 /* Release the DC */
7378 SelectObject(surface->hDC, surface->dib.holdbitmap);
7379 DeleteDC(surface->hDC);
7380 /* Release the DIB section */
7381 DeleteObject(surface->dib.DIBsection);
7382 surface->dib.bitmap_data = NULL;
7383 surface->resource.allocatedMemory = NULL;
7384 surface->Flags &= ~SFLAG_DIBSECTION;
7386 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7387 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7388 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7389 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7390 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7391 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7392 } else {
7393 surface->pow2Width = surface->pow2Height = 1;
7394 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7395 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7397 surface->glRect.left = 0;
7398 surface->glRect.top = 0;
7399 surface->glRect.right = surface->pow2Width;
7400 surface->glRect.bottom = surface->pow2Height;
7402 if(surface->glDescription.textureName) {
7403 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7404 ENTER_GL();
7405 glDeleteTextures(1, &surface->glDescription.textureName);
7406 LEAVE_GL();
7407 surface->glDescription.textureName = 0;
7408 surface->Flags &= ~SFLAG_CLIENT;
7410 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7411 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7412 surface->Flags |= SFLAG_NONPOW2;
7413 } else {
7414 surface->Flags &= ~SFLAG_NONPOW2;
7416 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7417 surface->resource.allocatedMemory = NULL;
7418 surface->resource.heapMemory = NULL;
7419 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7420 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7421 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7422 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7423 } else {
7424 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7428 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7429 TRACE("Unloading resource %p\n", resource);
7430 IWineD3DResource_UnLoad(resource);
7431 IWineD3DResource_Release(resource);
7432 return S_OK;
7435 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7437 UINT i, count;
7438 WINED3DDISPLAYMODE m;
7439 HRESULT hr;
7441 /* All Windowed modes are supported, as is leaving the current mode */
7442 if(pp->Windowed) return TRUE;
7443 if(!pp->BackBufferWidth) return TRUE;
7444 if(!pp->BackBufferHeight) return TRUE;
7446 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7447 for(i = 0; i < count; i++) {
7448 memset(&m, 0, sizeof(m));
7449 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7450 if(FAILED(hr)) {
7451 ERR("EnumAdapterModes failed\n");
7453 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7454 /* Mode found, it is supported */
7455 return TRUE;
7458 /* Mode not found -> not supported */
7459 return FALSE;
7462 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7464 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7465 UINT i;
7466 IWineD3DBaseShaderImpl *shader;
7468 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7469 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7470 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7473 ENTER_GL();
7474 if(This->depth_blt_texture) {
7475 glDeleteTextures(1, &This->depth_blt_texture);
7476 This->depth_blt_texture = 0;
7478 if (This->depth_blt_rb) {
7479 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7480 This->depth_blt_rb = 0;
7481 This->depth_blt_rb_w = 0;
7482 This->depth_blt_rb_h = 0;
7484 LEAVE_GL();
7486 This->blitter->free_private(iface);
7487 This->frag_pipe->free_private(iface);
7488 This->shader_backend->shader_free_private(iface);
7490 ENTER_GL();
7491 for (i = 0; i < GL_LIMITS(textures); i++) {
7492 /* Textures are recreated below */
7493 glDeleteTextures(1, &This->dummyTextureName[i]);
7494 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7495 This->dummyTextureName[i] = 0;
7497 LEAVE_GL();
7499 while(This->numContexts) {
7500 DestroyContext(This, This->contexts[0]);
7502 This->activeContext = NULL;
7503 HeapFree(GetProcessHeap(), 0, swapchain->context);
7504 swapchain->context = NULL;
7505 swapchain->num_contexts = 0;
7508 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7510 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7511 HRESULT hr;
7512 IWineD3DSurfaceImpl *target;
7514 /* Recreate the primary swapchain's context */
7515 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7516 if(swapchain->backBuffer) {
7517 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7518 } else {
7519 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7521 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7522 &swapchain->presentParms);
7523 swapchain->num_contexts = 1;
7524 This->activeContext = swapchain->context[0];
7526 create_dummy_textures(This);
7528 hr = This->shader_backend->shader_alloc_private(iface);
7529 if(FAILED(hr)) {
7530 ERR("Failed to recreate shader private data\n");
7531 goto err_out;
7533 hr = This->frag_pipe->alloc_private(iface);
7534 if(FAILED(hr)) {
7535 TRACE("Fragment pipeline private data couldn't be allocated\n");
7536 goto err_out;
7538 hr = This->blitter->alloc_private(iface);
7539 if(FAILED(hr)) {
7540 TRACE("Blitter private data couldn't be allocated\n");
7541 goto err_out;
7544 return WINED3D_OK;
7546 err_out:
7547 This->blitter->free_private(iface);
7548 This->frag_pipe->free_private(iface);
7549 This->shader_backend->shader_free_private(iface);
7550 return hr;
7553 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7555 IWineD3DSwapChainImpl *swapchain;
7556 HRESULT hr;
7557 BOOL DisplayModeChanged = FALSE;
7558 WINED3DDISPLAYMODE mode;
7559 TRACE("(%p)\n", This);
7561 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7562 if(FAILED(hr)) {
7563 ERR("Failed to get the first implicit swapchain\n");
7564 return hr;
7567 if(!is_display_mode_supported(This, pPresentationParameters)) {
7568 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7569 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7570 pPresentationParameters->BackBufferHeight);
7571 return WINED3DERR_INVALIDCALL;
7574 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7575 * on an existing gl context, so there's no real need for recreation.
7577 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7579 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7581 TRACE("New params:\n");
7582 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7583 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7584 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7585 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7586 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7587 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7588 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7589 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7590 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7591 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7592 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7593 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7594 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7596 /* No special treatment of these parameters. Just store them */
7597 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7598 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7599 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7600 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7602 /* What to do about these? */
7603 if(pPresentationParameters->BackBufferCount != 0 &&
7604 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7605 ERR("Cannot change the back buffer count yet\n");
7607 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7608 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7609 ERR("Cannot change the back buffer format yet\n");
7611 if(pPresentationParameters->hDeviceWindow != NULL &&
7612 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7613 ERR("Cannot change the device window yet\n");
7615 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7616 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7617 return WINED3DERR_INVALIDCALL;
7620 /* Reset the depth stencil */
7621 if (pPresentationParameters->EnableAutoDepthStencil)
7622 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7623 else
7624 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7626 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7628 if(pPresentationParameters->Windowed) {
7629 mode.Width = swapchain->orig_width;
7630 mode.Height = swapchain->orig_height;
7631 mode.RefreshRate = 0;
7632 mode.Format = swapchain->presentParms.BackBufferFormat;
7633 } else {
7634 mode.Width = pPresentationParameters->BackBufferWidth;
7635 mode.Height = pPresentationParameters->BackBufferHeight;
7636 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7637 mode.Format = swapchain->presentParms.BackBufferFormat;
7640 /* Should Width == 800 && Height == 0 set 800x600? */
7641 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7642 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7643 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7645 UINT i;
7647 if(!pPresentationParameters->Windowed) {
7648 DisplayModeChanged = TRUE;
7650 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7651 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7653 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7654 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7655 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7657 if(This->auto_depth_stencil_buffer) {
7658 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7662 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7663 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7664 DisplayModeChanged) {
7666 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7668 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7669 if(swapchain->presentParms.Windowed) {
7670 /* switch from windowed to fs */
7671 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7672 pPresentationParameters->BackBufferWidth,
7673 pPresentationParameters->BackBufferHeight);
7674 } else {
7675 /* Fullscreen -> fullscreen mode change */
7676 MoveWindow(swapchain->win_handle, 0, 0,
7677 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7678 TRUE);
7680 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7681 /* Fullscreen -> windowed switch */
7682 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7684 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7685 } else if(!pPresentationParameters->Windowed) {
7686 DWORD style = This->style, exStyle = This->exStyle;
7687 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7688 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7689 * Reset to clear up their mess. Guild Wars also loses the device during that.
7691 This->style = 0;
7692 This->exStyle = 0;
7693 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7694 pPresentationParameters->BackBufferWidth,
7695 pPresentationParameters->BackBufferHeight);
7696 This->style = style;
7697 This->exStyle = exStyle;
7700 TRACE("Resetting stateblock\n");
7701 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7702 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7704 /* Note: No parent needed for initial internal stateblock */
7705 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7706 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7707 else TRACE("Created stateblock %p\n", This->stateBlock);
7708 This->updateStateBlock = This->stateBlock;
7709 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7711 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7712 if(FAILED(hr)) {
7713 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7716 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7717 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7719 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7720 * first use
7722 return hr;
7725 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7727 /** FIXME: always true at the moment **/
7728 if(!bEnableDialogs) {
7729 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7731 return WINED3D_OK;
7735 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7737 TRACE("(%p) : pParameters %p\n", This, pParameters);
7739 *pParameters = This->createParms;
7740 return WINED3D_OK;
7743 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7744 IWineD3DSwapChain *swapchain;
7746 TRACE("Relaying to swapchain\n");
7748 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7749 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7750 IWineD3DSwapChain_Release(swapchain);
7752 return;
7755 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7756 IWineD3DSwapChain *swapchain;
7758 TRACE("Relaying to swapchain\n");
7760 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7761 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7762 IWineD3DSwapChain_Release(swapchain);
7764 return;
7768 /** ********************************************************
7769 * Notification functions
7770 ** ********************************************************/
7771 /** This function must be called in the release of a resource when ref == 0,
7772 * the contents of resource must still be correct,
7773 * any handles to other resource held by the caller must be closed
7774 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7775 *****************************************************/
7776 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7779 TRACE("(%p) : Adding Resource %p\n", This, resource);
7780 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7783 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7786 TRACE("(%p) : Removing resource %p\n", This, resource);
7788 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7792 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7794 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7795 int counter;
7797 TRACE("(%p) : resource %p\n", This, resource);
7799 context_resource_released(iface, resource, type);
7801 switch (type) {
7802 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7803 case WINED3DRTYPE_SURFACE: {
7804 unsigned int i;
7806 /* Cleanup any FBO attachments if d3d is enabled */
7807 if(This->d3d_initialized) {
7808 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7809 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7811 TRACE("Last active render target destroyed\n");
7812 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7813 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7814 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7815 * and the lastActiveRenderTarget member shouldn't matter
7817 if(swapchain) {
7818 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7819 TRACE("Activating primary back buffer\n");
7820 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7821 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7822 /* Single buffering environment */
7823 TRACE("Activating primary front buffer\n");
7824 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7825 } else {
7826 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7827 /* Implicit render target destroyed, that means the device is being destroyed
7828 * whatever we set here, it shouldn't matter
7830 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7832 } else {
7833 /* May happen during ddraw uninitialization */
7834 TRACE("Render target set, but swapchain does not exist!\n");
7835 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7839 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7840 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7841 This->render_targets[i] = NULL;
7844 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7845 This->stencilBufferTarget = NULL;
7849 break;
7851 case WINED3DRTYPE_TEXTURE:
7852 case WINED3DRTYPE_CUBETEXTURE:
7853 case WINED3DRTYPE_VOLUMETEXTURE:
7854 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7855 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7856 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7857 This->stateBlock->textures[counter] = NULL;
7859 if (This->updateStateBlock != This->stateBlock ){
7860 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7861 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7862 This->updateStateBlock->textures[counter] = NULL;
7866 break;
7867 case WINED3DRTYPE_VOLUME:
7868 /* TODO: nothing really? */
7869 break;
7870 case WINED3DRTYPE_VERTEXBUFFER:
7872 int streamNumber;
7873 TRACE("Cleaning up stream pointers\n");
7875 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7876 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7877 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7879 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7880 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7881 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7882 This->updateStateBlock->streamSource[streamNumber] = 0;
7883 /* Set changed flag? */
7886 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) */
7887 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7888 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7889 This->stateBlock->streamSource[streamNumber] = 0;
7894 break;
7895 case WINED3DRTYPE_INDEXBUFFER:
7896 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7897 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7898 This->updateStateBlock->pIndexData = NULL;
7901 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7902 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7903 This->stateBlock->pIndexData = NULL;
7906 break;
7908 case WINED3DRTYPE_BUFFER:
7909 /* Nothing to do, yet.*/
7910 break;
7912 default:
7913 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7914 break;
7918 /* Remove the resource from the resourceStore */
7919 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7921 TRACE("Resource released\n");
7925 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7927 IWineD3DResourceImpl *resource, *cursor;
7928 HRESULT ret;
7929 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7931 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7932 TRACE("enumerating resource %p\n", resource);
7933 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7934 ret = pCallback((IWineD3DResource *) resource, pData);
7935 if(ret == S_FALSE) {
7936 TRACE("Canceling enumeration\n");
7937 break;
7940 return WINED3D_OK;
7943 /**********************************************************
7944 * IWineD3DDevice VTbl follows
7945 **********************************************************/
7947 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7949 /*** IUnknown methods ***/
7950 IWineD3DDeviceImpl_QueryInterface,
7951 IWineD3DDeviceImpl_AddRef,
7952 IWineD3DDeviceImpl_Release,
7953 /*** IWineD3DDevice methods ***/
7954 IWineD3DDeviceImpl_GetParent,
7955 /*** Creation methods**/
7956 IWineD3DDeviceImpl_CreateBuffer,
7957 IWineD3DDeviceImpl_CreateVertexBuffer,
7958 IWineD3DDeviceImpl_CreateIndexBuffer,
7959 IWineD3DDeviceImpl_CreateStateBlock,
7960 IWineD3DDeviceImpl_CreateSurface,
7961 IWineD3DDeviceImpl_CreateRendertargetView,
7962 IWineD3DDeviceImpl_CreateTexture,
7963 IWineD3DDeviceImpl_CreateVolumeTexture,
7964 IWineD3DDeviceImpl_CreateVolume,
7965 IWineD3DDeviceImpl_CreateCubeTexture,
7966 IWineD3DDeviceImpl_CreateQuery,
7967 IWineD3DDeviceImpl_CreateSwapChain,
7968 IWineD3DDeviceImpl_CreateVertexDeclaration,
7969 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7970 IWineD3DDeviceImpl_CreateVertexShader,
7971 IWineD3DDeviceImpl_CreatePixelShader,
7972 IWineD3DDeviceImpl_CreatePalette,
7973 /*** Odd functions **/
7974 IWineD3DDeviceImpl_Init3D,
7975 IWineD3DDeviceImpl_InitGDI,
7976 IWineD3DDeviceImpl_Uninit3D,
7977 IWineD3DDeviceImpl_UninitGDI,
7978 IWineD3DDeviceImpl_SetMultithreaded,
7979 IWineD3DDeviceImpl_EvictManagedResources,
7980 IWineD3DDeviceImpl_GetAvailableTextureMem,
7981 IWineD3DDeviceImpl_GetBackBuffer,
7982 IWineD3DDeviceImpl_GetCreationParameters,
7983 IWineD3DDeviceImpl_GetDeviceCaps,
7984 IWineD3DDeviceImpl_GetDirect3D,
7985 IWineD3DDeviceImpl_GetDisplayMode,
7986 IWineD3DDeviceImpl_SetDisplayMode,
7987 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7988 IWineD3DDeviceImpl_GetRasterStatus,
7989 IWineD3DDeviceImpl_GetSwapChain,
7990 IWineD3DDeviceImpl_Reset,
7991 IWineD3DDeviceImpl_SetDialogBoxMode,
7992 IWineD3DDeviceImpl_SetCursorProperties,
7993 IWineD3DDeviceImpl_SetCursorPosition,
7994 IWineD3DDeviceImpl_ShowCursor,
7995 IWineD3DDeviceImpl_TestCooperativeLevel,
7996 /*** Getters and setters **/
7997 IWineD3DDeviceImpl_SetClipPlane,
7998 IWineD3DDeviceImpl_GetClipPlane,
7999 IWineD3DDeviceImpl_SetClipStatus,
8000 IWineD3DDeviceImpl_GetClipStatus,
8001 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8002 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8003 IWineD3DDeviceImpl_SetDepthStencilSurface,
8004 IWineD3DDeviceImpl_GetDepthStencilSurface,
8005 IWineD3DDeviceImpl_SetGammaRamp,
8006 IWineD3DDeviceImpl_GetGammaRamp,
8007 IWineD3DDeviceImpl_SetIndices,
8008 IWineD3DDeviceImpl_GetIndices,
8009 IWineD3DDeviceImpl_SetBaseVertexIndex,
8010 IWineD3DDeviceImpl_GetBaseVertexIndex,
8011 IWineD3DDeviceImpl_SetLight,
8012 IWineD3DDeviceImpl_GetLight,
8013 IWineD3DDeviceImpl_SetLightEnable,
8014 IWineD3DDeviceImpl_GetLightEnable,
8015 IWineD3DDeviceImpl_SetMaterial,
8016 IWineD3DDeviceImpl_GetMaterial,
8017 IWineD3DDeviceImpl_SetNPatchMode,
8018 IWineD3DDeviceImpl_GetNPatchMode,
8019 IWineD3DDeviceImpl_SetPaletteEntries,
8020 IWineD3DDeviceImpl_GetPaletteEntries,
8021 IWineD3DDeviceImpl_SetPixelShader,
8022 IWineD3DDeviceImpl_GetPixelShader,
8023 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8024 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8025 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8026 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8027 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8028 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8029 IWineD3DDeviceImpl_SetRenderState,
8030 IWineD3DDeviceImpl_GetRenderState,
8031 IWineD3DDeviceImpl_SetRenderTarget,
8032 IWineD3DDeviceImpl_GetRenderTarget,
8033 IWineD3DDeviceImpl_SetFrontBackBuffers,
8034 IWineD3DDeviceImpl_SetSamplerState,
8035 IWineD3DDeviceImpl_GetSamplerState,
8036 IWineD3DDeviceImpl_SetScissorRect,
8037 IWineD3DDeviceImpl_GetScissorRect,
8038 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8039 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8040 IWineD3DDeviceImpl_SetStreamSource,
8041 IWineD3DDeviceImpl_GetStreamSource,
8042 IWineD3DDeviceImpl_SetStreamSourceFreq,
8043 IWineD3DDeviceImpl_GetStreamSourceFreq,
8044 IWineD3DDeviceImpl_SetTexture,
8045 IWineD3DDeviceImpl_GetTexture,
8046 IWineD3DDeviceImpl_SetTextureStageState,
8047 IWineD3DDeviceImpl_GetTextureStageState,
8048 IWineD3DDeviceImpl_SetTransform,
8049 IWineD3DDeviceImpl_GetTransform,
8050 IWineD3DDeviceImpl_SetVertexDeclaration,
8051 IWineD3DDeviceImpl_GetVertexDeclaration,
8052 IWineD3DDeviceImpl_SetVertexShader,
8053 IWineD3DDeviceImpl_GetVertexShader,
8054 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8055 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8056 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8057 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8058 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8059 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8060 IWineD3DDeviceImpl_SetViewport,
8061 IWineD3DDeviceImpl_GetViewport,
8062 IWineD3DDeviceImpl_MultiplyTransform,
8063 IWineD3DDeviceImpl_ValidateDevice,
8064 IWineD3DDeviceImpl_ProcessVertices,
8065 /*** State block ***/
8066 IWineD3DDeviceImpl_BeginStateBlock,
8067 IWineD3DDeviceImpl_EndStateBlock,
8068 /*** Scene management ***/
8069 IWineD3DDeviceImpl_BeginScene,
8070 IWineD3DDeviceImpl_EndScene,
8071 IWineD3DDeviceImpl_Present,
8072 IWineD3DDeviceImpl_Clear,
8073 IWineD3DDeviceImpl_ClearRendertargetView,
8074 /*** Drawing ***/
8075 IWineD3DDeviceImpl_SetPrimitiveType,
8076 IWineD3DDeviceImpl_GetPrimitiveType,
8077 IWineD3DDeviceImpl_DrawPrimitive,
8078 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8079 IWineD3DDeviceImpl_DrawPrimitiveUP,
8080 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8081 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8082 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8083 IWineD3DDeviceImpl_DrawRectPatch,
8084 IWineD3DDeviceImpl_DrawTriPatch,
8085 IWineD3DDeviceImpl_DeletePatch,
8086 IWineD3DDeviceImpl_ColorFill,
8087 IWineD3DDeviceImpl_UpdateTexture,
8088 IWineD3DDeviceImpl_UpdateSurface,
8089 IWineD3DDeviceImpl_GetFrontBufferData,
8090 /*** object tracking ***/
8091 IWineD3DDeviceImpl_ResourceReleased,
8092 IWineD3DDeviceImpl_EnumResources
8095 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8096 WINED3DRS_ALPHABLENDENABLE ,
8097 WINED3DRS_ALPHAFUNC ,
8098 WINED3DRS_ALPHAREF ,
8099 WINED3DRS_ALPHATESTENABLE ,
8100 WINED3DRS_BLENDOP ,
8101 WINED3DRS_COLORWRITEENABLE ,
8102 WINED3DRS_DESTBLEND ,
8103 WINED3DRS_DITHERENABLE ,
8104 WINED3DRS_FILLMODE ,
8105 WINED3DRS_FOGDENSITY ,
8106 WINED3DRS_FOGEND ,
8107 WINED3DRS_FOGSTART ,
8108 WINED3DRS_LASTPIXEL ,
8109 WINED3DRS_SHADEMODE ,
8110 WINED3DRS_SRCBLEND ,
8111 WINED3DRS_STENCILENABLE ,
8112 WINED3DRS_STENCILFAIL ,
8113 WINED3DRS_STENCILFUNC ,
8114 WINED3DRS_STENCILMASK ,
8115 WINED3DRS_STENCILPASS ,
8116 WINED3DRS_STENCILREF ,
8117 WINED3DRS_STENCILWRITEMASK ,
8118 WINED3DRS_STENCILZFAIL ,
8119 WINED3DRS_TEXTUREFACTOR ,
8120 WINED3DRS_WRAP0 ,
8121 WINED3DRS_WRAP1 ,
8122 WINED3DRS_WRAP2 ,
8123 WINED3DRS_WRAP3 ,
8124 WINED3DRS_WRAP4 ,
8125 WINED3DRS_WRAP5 ,
8126 WINED3DRS_WRAP6 ,
8127 WINED3DRS_WRAP7 ,
8128 WINED3DRS_ZENABLE ,
8129 WINED3DRS_ZFUNC ,
8130 WINED3DRS_ZWRITEENABLE
8133 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8134 WINED3DTSS_ALPHAARG0 ,
8135 WINED3DTSS_ALPHAARG1 ,
8136 WINED3DTSS_ALPHAARG2 ,
8137 WINED3DTSS_ALPHAOP ,
8138 WINED3DTSS_BUMPENVLOFFSET ,
8139 WINED3DTSS_BUMPENVLSCALE ,
8140 WINED3DTSS_BUMPENVMAT00 ,
8141 WINED3DTSS_BUMPENVMAT01 ,
8142 WINED3DTSS_BUMPENVMAT10 ,
8143 WINED3DTSS_BUMPENVMAT11 ,
8144 WINED3DTSS_COLORARG0 ,
8145 WINED3DTSS_COLORARG1 ,
8146 WINED3DTSS_COLORARG2 ,
8147 WINED3DTSS_COLOROP ,
8148 WINED3DTSS_RESULTARG ,
8149 WINED3DTSS_TEXCOORDINDEX ,
8150 WINED3DTSS_TEXTURETRANSFORMFLAGS
8153 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8154 WINED3DSAMP_ADDRESSU ,
8155 WINED3DSAMP_ADDRESSV ,
8156 WINED3DSAMP_ADDRESSW ,
8157 WINED3DSAMP_BORDERCOLOR ,
8158 WINED3DSAMP_MAGFILTER ,
8159 WINED3DSAMP_MINFILTER ,
8160 WINED3DSAMP_MIPFILTER ,
8161 WINED3DSAMP_MIPMAPLODBIAS ,
8162 WINED3DSAMP_MAXMIPLEVEL ,
8163 WINED3DSAMP_MAXANISOTROPY ,
8164 WINED3DSAMP_SRGBTEXTURE ,
8165 WINED3DSAMP_ELEMENTINDEX
8168 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8169 WINED3DRS_AMBIENT ,
8170 WINED3DRS_AMBIENTMATERIALSOURCE ,
8171 WINED3DRS_CLIPPING ,
8172 WINED3DRS_CLIPPLANEENABLE ,
8173 WINED3DRS_COLORVERTEX ,
8174 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8175 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8176 WINED3DRS_FOGDENSITY ,
8177 WINED3DRS_FOGEND ,
8178 WINED3DRS_FOGSTART ,
8179 WINED3DRS_FOGTABLEMODE ,
8180 WINED3DRS_FOGVERTEXMODE ,
8181 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8182 WINED3DRS_LIGHTING ,
8183 WINED3DRS_LOCALVIEWER ,
8184 WINED3DRS_MULTISAMPLEANTIALIAS ,
8185 WINED3DRS_MULTISAMPLEMASK ,
8186 WINED3DRS_NORMALIZENORMALS ,
8187 WINED3DRS_PATCHEDGESTYLE ,
8188 WINED3DRS_POINTSCALE_A ,
8189 WINED3DRS_POINTSCALE_B ,
8190 WINED3DRS_POINTSCALE_C ,
8191 WINED3DRS_POINTSCALEENABLE ,
8192 WINED3DRS_POINTSIZE ,
8193 WINED3DRS_POINTSIZE_MAX ,
8194 WINED3DRS_POINTSIZE_MIN ,
8195 WINED3DRS_POINTSPRITEENABLE ,
8196 WINED3DRS_RANGEFOGENABLE ,
8197 WINED3DRS_SPECULARMATERIALSOURCE ,
8198 WINED3DRS_TWEENFACTOR ,
8199 WINED3DRS_VERTEXBLEND ,
8200 WINED3DRS_CULLMODE ,
8201 WINED3DRS_FOGCOLOR
8204 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8205 WINED3DTSS_TEXCOORDINDEX ,
8206 WINED3DTSS_TEXTURETRANSFORMFLAGS
8209 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8210 WINED3DSAMP_DMAPOFFSET
8213 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8214 DWORD rep = This->StateTable[state].representative;
8215 DWORD idx;
8216 BYTE shift;
8217 UINT i;
8218 WineD3DContext *context;
8220 if(!rep) return;
8221 for(i = 0; i < This->numContexts; i++) {
8222 context = This->contexts[i];
8223 if(isStateDirty(context, rep)) continue;
8225 context->dirtyArray[context->numDirtyEntries++] = rep;
8226 idx = rep >> 5;
8227 shift = rep & 0x1f;
8228 context->isStateDirty[idx] |= (1 << shift);
8232 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8233 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8234 /* The drawable size of a pbuffer render target is the current pbuffer size
8236 *width = dev->pbufferWidth;
8237 *height = dev->pbufferHeight;
8240 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8241 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8243 *width = This->pow2Width;
8244 *height = This->pow2Height;
8247 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8248 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8249 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8250 * current context's drawable, which is the size of the back buffer of the swapchain
8251 * the active context belongs to. The back buffer of the swapchain is stored as the
8252 * surface the context belongs to.
8254 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8255 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;