d3d8, d3d9: Don't rely on the wined3d buffer type.
[wine/hacks.git] / dlls / wined3d / device.c
blobca47eb380a2c064a01e50142d8a5b43677a20fa1
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->element_count; ++i)
190 const struct wined3d_vertex_declaration_element *element = &declaration->elements[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->elements,
198 element, i + 1, declaration->element_count);
200 if (!This->stateBlock->streamSource[element->input_slot]) continue;
202 stride = This->stateBlock->streamStride[element->input_slot];
203 if (This->stateBlock->streamIsUP)
205 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
206 buffer_object = 0;
207 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
209 else
211 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 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->input_slot])->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 %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
251 if (use_vshader)
253 if (element->output_slot == ~0U)
255 /* TODO: Assuming vertexdeclarations are usually used with the
256 * same or a similar shader, it might be worth it to store the
257 * last used output slot and try that one first. */
258 stride_used = vshader_get_input(This->stateBlock->vertexShader,
259 element->usage, element->usage_idx, &idx);
261 else
263 idx = element->output_slot;
264 stride_used = TRUE;
267 else
269 if (!element->ffp_valid)
271 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
272 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
273 stride_used = FALSE;
275 else
277 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
281 if (stride_used)
283 TRACE("Load %s array %u [usage %s, usage_idx %u, "
284 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
285 use_vshader ? "shader": "fixed function", idx,
286 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
287 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
289 stream_info->elements[idx].format_desc = element->format_desc;
290 stream_info->elements[idx].stride = stride;
291 stream_info->elements[idx].data = data;
292 stream_info->elements[idx].stream_idx = element->input_slot;
293 stream_info->elements[idx].buffer_object = buffer_object;
295 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
297 stream_info->swizzle_map |= 1 << idx;
299 stream_info->use_map |= 1 << idx;
303 /* Now call PreLoad on all the vertex buffers. In the very rare case
304 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
305 * The vertex buffer can now use the strided structure in the device instead of finding its
306 * own again.
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
309 * once in there. */
310 for (i = 0; i < stream_count; ++i)
312 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
313 if (vb) IWineD3DBuffer_PreLoad(vb);
317 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
318 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
320 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
321 e->format_desc = format_desc;
322 e->stride = strided->dwStride;
323 e->data = strided->lpData;
324 e->stream_idx = 0;
325 e->buffer_object = 0;
328 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
329 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
331 unsigned int i;
333 memset(stream_info, 0, sizeof(*stream_info));
335 if (strided->position.lpData)
336 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
337 if (strided->normal.lpData)
338 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
339 if (strided->diffuse.lpData)
340 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
341 if (strided->specular.lpData)
342 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
344 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
346 if (strided->texCoords[i].lpData)
347 stream_info_element_from_strided(This, &strided->texCoords[i],
348 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
351 stream_info->position_transformed = strided->position_transformed;
353 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
355 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
357 stream_info->swizzle_map |= 1 << i;
359 stream_info->use_map |= 1 << i;
363 /**********************************************************
364 * IUnknown parts follows
365 **********************************************************/
367 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
371 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
372 if (IsEqualGUID(riid, &IID_IUnknown)
373 || IsEqualGUID(riid, &IID_IWineD3DBase)
374 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
375 IUnknown_AddRef(iface);
376 *ppobj = This;
377 return S_OK;
379 *ppobj = NULL;
380 return E_NOINTERFACE;
383 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
385 ULONG refCount = InterlockedIncrement(&This->ref);
387 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
388 return refCount;
391 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 ULONG refCount = InterlockedDecrement(&This->ref);
395 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
397 if (!refCount) {
398 UINT i;
400 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
401 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
402 This->multistate_funcs[i] = NULL;
405 /* TODO: Clean up all the surfaces and textures! */
406 /* NOTE: You must release the parent if the object was created via a callback
407 ** ***************************/
409 if (!list_empty(&This->resources)) {
410 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
411 dumpResources(&This->resources);
414 if(This->contexts) ERR("Context array not freed!\n");
415 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
416 This->haveHardwareCursor = FALSE;
418 IWineD3D_Release(This->wineD3D);
419 This->wineD3D = NULL;
420 HeapFree(GetProcessHeap(), 0, This);
421 TRACE("Freed device %p\n", This);
422 This = NULL;
424 return refCount;
427 /**********************************************************
428 * IWineD3DDevice implementation follows
429 **********************************************************/
430 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 *pParent = This->parent;
433 IUnknown_AddRef(This->parent);
434 return WINED3D_OK;
437 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
438 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 struct wined3d_buffer *object;
442 HRESULT hr;
444 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
446 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
447 if (!object)
449 ERR("Failed to allocate memory\n");
450 return E_OUTOFMEMORY;
453 object->vtbl = &wined3d_buffer_vtbl;
454 object->desc = *desc;
456 FIXME("Ignoring access flags (pool)\n");
458 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
459 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
460 if (FAILED(hr))
462 WARN("Failed to initialize resource, returning %#x\n", hr);
463 HeapFree(GetProcessHeap(), 0, object);
464 return hr;
467 TRACE("Created resource %p\n", object);
469 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
471 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
472 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
474 if (data)
476 BYTE *ptr;
478 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
479 if (FAILED(hr))
481 ERR("Failed to map buffer, hr %#x\n", hr);
482 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
483 return hr;
486 memcpy(ptr, data, desc->byte_width);
488 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
489 if (FAILED(hr))
491 ERR("Failed to unmap buffer, hr %#x\n", hr);
492 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
493 return hr;
497 *buffer = (IWineD3DBuffer *)object;
499 return WINED3D_OK;
502 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
503 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
506 /* Dummy format for now */
507 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
508 struct wined3d_buffer *object;
509 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
510 HRESULT hr;
511 BOOL conv;
513 if(Size == 0) {
514 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
515 *ppVertexBuffer = NULL;
516 return WINED3DERR_INVALIDCALL;
517 } else if(Pool == WINED3DPOOL_SCRATCH) {
518 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
519 * anyway, SCRATCH vertex buffers aren't usable anywhere
521 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
522 *ppVertexBuffer = NULL;
523 return WINED3DERR_INVALIDCALL;
526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
527 if (!object)
529 ERR("Out of memory\n");
530 *ppVertexBuffer = NULL;
531 return WINED3DERR_OUTOFVIDEOMEMORY;
534 object->vtbl = &wined3d_buffer_vtbl;
535 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
536 if (FAILED(hr))
538 WARN("Failed to initialize resource, returning %#x\n", hr);
539 HeapFree(GetProcessHeap(), 0, object);
540 *ppVertexBuffer = NULL;
541 return hr;
544 TRACE("(%p) : Created resource %p\n", This, object);
546 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
548 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);
549 *ppVertexBuffer = (IWineD3DBuffer *)object;
551 object->fvf = FVF;
553 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
554 * drawStridedFast (half-life 2).
556 * Basically converting the vertices in the buffer is quite expensive, and observations
557 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
558 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
560 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
561 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
562 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
563 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
564 * dx7 apps.
565 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
566 * more. In this call we can convert dx7 buffers too.
568 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
569 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
570 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
571 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
572 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
573 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
574 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
575 } else if(dxVersion <= 7 && conv) {
576 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
577 } else {
578 object->flags |= WINED3D_BUFFER_CREATEBO;
580 return WINED3D_OK;
583 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
584 GLenum error, glUsage;
585 TRACE("Creating VBO for Index Buffer %p\n", object);
587 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
588 * restored on the next draw
590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
592 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
593 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
594 ENTER_GL();
596 while(glGetError());
598 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
599 error = glGetError();
600 if(error != GL_NO_ERROR || object->vbo == 0) {
601 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
602 goto out;
605 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
606 error = glGetError();
607 if(error != GL_NO_ERROR) {
608 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
609 goto out;
612 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
613 * copy no readback will be needed
615 glUsage = GL_STATIC_DRAW_ARB;
616 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
617 error = glGetError();
618 if(error != GL_NO_ERROR) {
619 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
620 goto out;
622 LEAVE_GL();
623 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
624 return;
626 out:
627 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
628 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
629 LEAVE_GL();
630 object->vbo = 0;
633 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
634 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
635 HANDLE *sharedHandle, IUnknown *parent) {
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
638 IWineD3DIndexBufferImpl *object;
639 HRESULT hr;
641 TRACE("(%p) Creating index buffer\n", This);
643 /* Allocate the storage for the device */
644 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
645 if (!object)
647 ERR("Out of memory\n");
648 *ppIndexBuffer = NULL;
649 return WINED3DERR_OUTOFVIDEOMEMORY;
652 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
653 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
654 if (FAILED(hr))
656 WARN("Failed to initialize resource, returning %#x\n", hr);
657 HeapFree(GetProcessHeap(), 0, object);
658 *ppIndexBuffer = NULL;
659 return hr;
662 TRACE("(%p) : Created resource %p\n", This, object);
664 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
666 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
667 CreateIndexBufferVBO(This, object);
670 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
671 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
672 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
674 return WINED3D_OK;
677 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 IWineD3DStateBlockImpl *object;
681 unsigned int i, j;
682 HRESULT temp_result;
684 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
685 if(!object)
687 ERR("Out of memory\n");
688 *ppStateBlock = NULL;
689 return WINED3DERR_OUTOFVIDEOMEMORY;
692 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
693 object->wineD3DDevice = This;
694 object->parent = parent;
695 object->ref = 1;
696 object->blockType = Type;
698 *ppStateBlock = (IWineD3DStateBlock *)object;
700 for(i = 0; i < LIGHTMAP_SIZE; i++) {
701 list_init(&object->lightMap[i]);
704 temp_result = allocate_shader_constants(object);
705 if (FAILED(temp_result))
707 HeapFree(GetProcessHeap(), 0, object);
708 return temp_result;
711 /* Special case - Used during initialization to produce a placeholder stateblock
712 so other functions called can update a state block */
713 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
715 /* Don't bother increasing the reference count otherwise a device will never
716 be freed due to circular dependencies */
717 return WINED3D_OK;
720 /* Otherwise, might as well set the whole state block to the appropriate values */
721 if (This->stateBlock != NULL)
722 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
723 else
724 memset(object->streamFreq, 1, sizeof(object->streamFreq));
726 /* Reset the ref and type after kludging it */
727 object->wineD3DDevice = This;
728 object->ref = 1;
729 object->blockType = Type;
731 TRACE("Updating changed flags appropriate for type %d\n", Type);
733 if (Type == WINED3DSBT_ALL) {
735 TRACE("ALL => Pretend everything has changed\n");
736 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
738 /* Lights are not part of the changed / set structure */
739 for(j = 0; j < LIGHTMAP_SIZE; j++) {
740 struct list *e;
741 LIST_FOR_EACH(e, &object->lightMap[j]) {
742 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
743 light->changed = TRUE;
744 light->enabledChanged = TRUE;
747 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
748 object->contained_render_states[j - 1] = j;
750 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
751 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
752 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
753 object->contained_transform_states[j - 1] = j;
755 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
756 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
757 object->contained_vs_consts_f[j] = j;
759 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
760 for(j = 0; j < MAX_CONST_I; j++) {
761 object->contained_vs_consts_i[j] = j;
763 object->num_contained_vs_consts_i = MAX_CONST_I;
764 for(j = 0; j < MAX_CONST_B; j++) {
765 object->contained_vs_consts_b[j] = j;
767 object->num_contained_vs_consts_b = MAX_CONST_B;
768 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
769 object->contained_ps_consts_f[j] = j;
771 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
772 for(j = 0; j < MAX_CONST_I; j++) {
773 object->contained_ps_consts_i[j] = j;
775 object->num_contained_ps_consts_i = MAX_CONST_I;
776 for(j = 0; j < MAX_CONST_B; j++) {
777 object->contained_ps_consts_b[j] = j;
779 object->num_contained_ps_consts_b = MAX_CONST_B;
780 for(i = 0; i < MAX_TEXTURES; i++) {
781 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
783 object->contained_tss_states[object->num_contained_tss_states].stage = i;
784 object->contained_tss_states[object->num_contained_tss_states].state = j;
785 object->num_contained_tss_states++;
788 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
789 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
790 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
791 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
792 object->num_contained_sampler_states++;
796 for(i = 0; i < MAX_STREAMS; i++) {
797 if(object->streamSource[i]) {
798 IWineD3DBuffer_AddRef(object->streamSource[i]);
801 if(object->pIndexData) {
802 IWineD3DIndexBuffer_AddRef(object->pIndexData);
804 if(object->vertexShader) {
805 IWineD3DVertexShader_AddRef(object->vertexShader);
807 if(object->pixelShader) {
808 IWineD3DPixelShader_AddRef(object->pixelShader);
811 } else if (Type == WINED3DSBT_PIXELSTATE) {
813 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
814 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
816 object->changed.pixelShader = TRUE;
818 /* Pixel Shader Constants */
819 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
820 object->contained_ps_consts_f[i] = i;
821 object->changed.pixelShaderConstantsF[i] = TRUE;
823 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
824 for (i = 0; i < MAX_CONST_B; ++i) {
825 object->contained_ps_consts_b[i] = i;
826 object->changed.pixelShaderConstantsB |= (1 << i);
828 object->num_contained_ps_consts_b = MAX_CONST_B;
829 for (i = 0; i < MAX_CONST_I; ++i) {
830 object->contained_ps_consts_i[i] = i;
831 object->changed.pixelShaderConstantsI |= (1 << i);
833 object->num_contained_ps_consts_i = MAX_CONST_I;
835 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
836 DWORD rs = SavedPixelStates_R[i];
837 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
838 object->contained_render_states[i] = rs;
840 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
841 for (j = 0; j < MAX_TEXTURES; j++) {
842 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
843 DWORD state = SavedPixelStates_T[i];
844 object->changed.textureState[j] |= 1 << state;
845 object->contained_tss_states[object->num_contained_tss_states].stage = j;
846 object->contained_tss_states[object->num_contained_tss_states].state = state;
847 object->num_contained_tss_states++;
850 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
851 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
852 DWORD state = SavedPixelStates_S[i];
853 object->changed.samplerState[j] |= 1 << state;
854 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
855 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
856 object->num_contained_sampler_states++;
859 if(object->pixelShader) {
860 IWineD3DPixelShader_AddRef(object->pixelShader);
863 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
864 * on them. This makes releasing the buffer easier
866 for(i = 0; i < MAX_STREAMS; i++) {
867 object->streamSource[i] = NULL;
869 object->pIndexData = NULL;
870 object->vertexShader = NULL;
872 } else if (Type == WINED3DSBT_VERTEXSTATE) {
874 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
875 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
877 object->changed.vertexShader = TRUE;
879 /* Vertex Shader Constants */
880 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
881 object->changed.vertexShaderConstantsF[i] = TRUE;
882 object->contained_vs_consts_f[i] = i;
884 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
885 for (i = 0; i < MAX_CONST_B; ++i) {
886 object->contained_vs_consts_b[i] = i;
887 object->changed.vertexShaderConstantsB |= (1 << i);
889 object->num_contained_vs_consts_b = MAX_CONST_B;
890 for (i = 0; i < MAX_CONST_I; ++i) {
891 object->contained_vs_consts_i[i] = i;
892 object->changed.vertexShaderConstantsI |= (1 << i);
894 object->num_contained_vs_consts_i = MAX_CONST_I;
895 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
896 DWORD rs = SavedVertexStates_R[i];
897 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
898 object->contained_render_states[i] = rs;
900 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
901 for (j = 0; j < MAX_TEXTURES; j++) {
902 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
903 DWORD state = SavedVertexStates_T[i];
904 object->changed.textureState[j] |= 1 << state;
905 object->contained_tss_states[object->num_contained_tss_states].stage = j;
906 object->contained_tss_states[object->num_contained_tss_states].state = state;
907 object->num_contained_tss_states++;
910 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
911 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
912 DWORD state = SavedVertexStates_S[i];
913 object->changed.samplerState[j] |= 1 << state;
914 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
915 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
916 object->num_contained_sampler_states++;
920 for(j = 0; j < LIGHTMAP_SIZE; j++) {
921 struct list *e;
922 LIST_FOR_EACH(e, &object->lightMap[j]) {
923 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
924 light->changed = TRUE;
925 light->enabledChanged = TRUE;
929 for(i = 0; i < MAX_STREAMS; i++) {
930 if(object->streamSource[i]) {
931 IWineD3DBuffer_AddRef(object->streamSource[i]);
934 if(object->vertexShader) {
935 IWineD3DVertexShader_AddRef(object->vertexShader);
937 object->pIndexData = NULL;
938 object->pixelShader = NULL;
939 } else {
940 FIXME("Unrecognized state block type %d\n", Type);
943 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
944 return WINED3D_OK;
947 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) {
948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
949 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
950 unsigned int Size = 1;
951 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
952 UINT mul_4w, mul_4h;
953 HRESULT hr;
955 TRACE("(%p) Create surface\n",This);
957 if(MultisampleQuality > 0) {
958 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
959 MultisampleQuality=0;
962 /** FIXME: Check that the format is supported
963 * by the device.
964 *******************************/
966 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
967 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
968 * space!
969 *********************************/
970 mul_4w = (Width + 3) & ~3;
971 mul_4h = (Height + 3) & ~3;
972 if (WINED3DFMT_UNKNOWN == Format) {
973 Size = 0;
974 } else if (Format == WINED3DFMT_DXT1) {
975 /* DXT1 is half byte per pixel */
976 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
978 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
979 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
980 Format == WINED3DFMT_ATI2N) {
981 Size = (mul_4w * glDesc->byte_count * mul_4h);
982 } else {
983 /* The pitch is a multiple of 4 bytes */
984 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
985 Size *= Height;
988 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
990 /** Create and initialise the surface resource **/
991 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
992 if (!object)
994 ERR("Out of memory\n");
995 *ppSurface = NULL;
996 return WINED3DERR_OUTOFVIDEOMEMORY;
999 /* Look at the implementation and set the correct Vtable */
1000 switch(Impl)
1002 case SURFACE_OPENGL:
1003 /* Check if a 3D adapter is available when creating gl surfaces */
1004 if (!This->adapter)
1006 ERR("OpenGL surfaces are not available without opengl\n");
1007 HeapFree(GetProcessHeap(), 0, object);
1008 return WINED3DERR_NOTAVAILABLE;
1010 object->lpVtbl = &IWineD3DSurface_Vtbl;
1011 break;
1013 case SURFACE_GDI:
1014 object->lpVtbl = &IWineGDISurface_Vtbl;
1015 break;
1017 default:
1018 /* To be sure to catch this */
1019 ERR("Unknown requested surface implementation %d!\n", Impl);
1020 HeapFree(GetProcessHeap(), 0, object);
1021 return WINED3DERR_INVALIDCALL;
1024 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
1025 if (FAILED(hr))
1027 WARN("Failed to initialize resource, returning %#x\n", hr);
1028 HeapFree(GetProcessHeap(), 0, object);
1029 *ppSurface = NULL;
1030 return hr;
1033 TRACE("(%p) : Created resource %p\n", This, object);
1035 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1037 *ppSurface = (IWineD3DSurface *)object;
1039 /* "Standalone" surface */
1040 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1042 object->currentDesc.Width = Width;
1043 object->currentDesc.Height = Height;
1044 object->currentDesc.MultiSampleType = MultiSample;
1045 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1046 object->glDescription.level = Level;
1047 list_init(&object->overlays);
1049 /* Flags */
1050 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1051 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1052 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1053 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1055 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1057 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1058 * this function is too deep to need to care about things like this.
1059 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1060 * ****************************************/
1061 switch(Pool) {
1062 case WINED3DPOOL_SCRATCH:
1063 if(!Lockable)
1064 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1065 "which are mutually exclusive, setting lockable to TRUE\n");
1066 Lockable = TRUE;
1067 break;
1068 case WINED3DPOOL_SYSTEMMEM:
1069 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1070 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1071 case WINED3DPOOL_MANAGED:
1072 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1073 "Usage of DYNAMIC which are mutually exclusive, not doing "
1074 "anything just telling you.\n");
1075 break;
1076 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1077 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1078 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1079 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1080 break;
1081 default:
1082 FIXME("(%p) Unknown pool %d\n", This, Pool);
1083 break;
1086 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1087 FIXME("Trying to create a render target that isn't in the default pool\n");
1090 /* mark the texture as dirty so that it gets loaded first time around*/
1091 surface_add_dirty_rect(*ppSurface, NULL);
1092 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1093 This, Width, Height, Format, debug_d3dformat(Format),
1094 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1096 list_init(&object->renderbuffers);
1098 /* Call the private setup routine */
1099 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1100 if (FAILED(hr))
1102 ERR("Private setup failed, returning %#x\n", hr);
1103 IWineD3DSurface_Release(*ppSurface);
1104 *ppSurface = NULL;
1105 return hr;
1108 return hr;
1111 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1112 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1114 struct wined3d_rendertarget_view *object;
1116 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1117 if (!object)
1119 ERR("Failed to allocate memory\n");
1120 return E_OUTOFMEMORY;
1123 object->vtbl = &wined3d_rendertarget_view_vtbl;
1124 object->refcount = 1;
1125 IWineD3DResource_AddRef(resource);
1126 object->resource = resource;
1127 object->parent = parent;
1129 *rendertarget_view = (IWineD3DRendertargetView *)object;
1131 return WINED3D_OK;
1134 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1135 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1136 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
1138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1139 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1140 IWineD3DTextureImpl *object;
1141 unsigned int i;
1142 UINT tmpW;
1143 UINT tmpH;
1144 HRESULT hr;
1145 unsigned int pow2Width;
1146 unsigned int pow2Height;
1148 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1149 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1150 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1152 /* TODO: It should only be possible to create textures for formats
1153 that are reported as supported */
1154 if (WINED3DFMT_UNKNOWN >= Format) {
1155 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1156 return WINED3DERR_INVALIDCALL;
1159 /* Non-power2 support */
1160 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1162 pow2Width = Width;
1163 pow2Height = Height;
1165 else
1167 /* Find the nearest pow2 match */
1168 pow2Width = pow2Height = 1;
1169 while (pow2Width < Width) pow2Width <<= 1;
1170 while (pow2Height < Height) pow2Height <<= 1;
1172 if (pow2Width != Width || pow2Height != Height)
1174 if (Levels > 1)
1176 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1177 return WINED3DERR_INVALIDCALL;
1179 Levels = 1;
1183 /* Calculate levels for mip mapping */
1184 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1186 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1188 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1189 return WINED3DERR_INVALIDCALL;
1192 if (Levels > 1)
1194 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1195 return WINED3DERR_INVALIDCALL;
1198 Levels = 1;
1200 else if (!Levels)
1202 Levels = wined3d_log2i(max(Width, Height)) + 1;
1203 TRACE("Calculated levels = %d\n", Levels);
1206 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1207 if (!object)
1209 ERR("Out of memory\n");
1210 *ppTexture = NULL;
1211 return WINED3DERR_OUTOFVIDEOMEMORY;
1214 object->lpVtbl = &IWineD3DTexture_Vtbl;
1215 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1216 if (FAILED(hr))
1218 WARN("Failed to initialize resource, returning %#x\n", hr);
1219 HeapFree(GetProcessHeap(), 0, object);
1220 *ppTexture = NULL;
1221 return hr;
1224 TRACE("(%p) : Created resource %p\n", This, object);
1226 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1228 *ppTexture = (IWineD3DTexture *)object;
1230 basetexture_init(&object->baseTexture, Levels, Usage);
1232 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1234 object->baseTexture.minMipLookup = minMipLookup;
1235 object->baseTexture.magLookup = magLookup;
1236 } else {
1237 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1238 object->baseTexture.magLookup = magLookup_noFilter;
1241 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1242 /* Precalculated scaling for 'faked' non power of two texture coords.
1243 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1244 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1245 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1247 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1248 object->baseTexture.pow2Matrix[0] = 1.0;
1249 object->baseTexture.pow2Matrix[5] = 1.0;
1250 object->baseTexture.pow2Matrix[10] = 1.0;
1251 object->baseTexture.pow2Matrix[15] = 1.0;
1252 object->target = GL_TEXTURE_2D;
1253 object->cond_np2 = TRUE;
1254 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1255 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1256 (Width != pow2Width || Height != pow2Height) &&
1257 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1259 if ((Width != 1) || (Height != 1)) {
1260 object->baseTexture.pow2Matrix_identity = FALSE;
1263 object->baseTexture.pow2Matrix[0] = (float)Width;
1264 object->baseTexture.pow2Matrix[5] = (float)Height;
1265 object->baseTexture.pow2Matrix[10] = 1.0;
1266 object->baseTexture.pow2Matrix[15] = 1.0;
1267 object->target = GL_TEXTURE_RECTANGLE_ARB;
1268 object->cond_np2 = TRUE;
1269 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1270 } else {
1271 if ((Width != pow2Width) || (Height != pow2Height)) {
1272 object->baseTexture.pow2Matrix_identity = FALSE;
1273 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1274 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1275 } else {
1276 object->baseTexture.pow2Matrix[0] = 1.0;
1277 object->baseTexture.pow2Matrix[5] = 1.0;
1280 object->baseTexture.pow2Matrix[10] = 1.0;
1281 object->baseTexture.pow2Matrix[15] = 1.0;
1282 object->target = GL_TEXTURE_2D;
1283 object->cond_np2 = FALSE;
1285 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1287 /* Generate all the surfaces */
1288 tmpW = Width;
1289 tmpH = Height;
1290 for (i = 0; i < object->baseTexture.levels; i++)
1292 /* use the callback to create the texture surface */
1293 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1294 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1295 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1296 FIXME("Failed to create surface %p\n", object);
1297 /* clean up */
1298 object->surfaces[i] = NULL;
1299 IWineD3DTexture_Release((IWineD3DTexture *)object);
1301 *ppTexture = NULL;
1302 return hr;
1305 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1306 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1307 surface_set_texture_target(object->surfaces[i], object->target);
1308 /* calculate the next mipmap level */
1309 tmpW = max(1, tmpW >> 1);
1310 tmpH = max(1, tmpH >> 1);
1312 object->baseTexture.internal_preload = texture_internal_preload;
1314 TRACE("(%p) : Created texture %p\n", This, object);
1315 return WINED3D_OK;
1318 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1319 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1320 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1323 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1324 IWineD3DVolumeTextureImpl *object;
1325 unsigned int i;
1326 UINT tmpW;
1327 UINT tmpH;
1328 UINT tmpD;
1329 HRESULT hr;
1331 /* TODO: It should only be possible to create textures for formats
1332 that are reported as supported */
1333 if (WINED3DFMT_UNKNOWN >= Format) {
1334 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1335 return WINED3DERR_INVALIDCALL;
1337 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1338 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1339 return WINED3DERR_INVALIDCALL;
1342 /* Calculate levels for mip mapping */
1343 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1345 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1347 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1348 return WINED3DERR_INVALIDCALL;
1351 if (Levels > 1)
1353 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1354 return WINED3DERR_INVALIDCALL;
1357 Levels = 1;
1359 else if (!Levels)
1361 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1362 TRACE("Calculated levels = %d\n", Levels);
1365 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1366 if (!object)
1368 ERR("Out of memory\n");
1369 *ppVolumeTexture = NULL;
1370 return WINED3DERR_OUTOFVIDEOMEMORY;
1373 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1374 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1375 if (FAILED(hr))
1377 WARN("Failed to initialize resource, returning %#x\n", hr);
1378 HeapFree(GetProcessHeap(), 0, object);
1379 *ppVolumeTexture = NULL;
1380 return hr;
1383 TRACE("(%p) : Created resource %p\n", This, object);
1385 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1387 basetexture_init(&object->baseTexture, Levels, Usage);
1389 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1390 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1392 /* Is NP2 support for volumes needed? */
1393 object->baseTexture.pow2Matrix[ 0] = 1.0;
1394 object->baseTexture.pow2Matrix[ 5] = 1.0;
1395 object->baseTexture.pow2Matrix[10] = 1.0;
1396 object->baseTexture.pow2Matrix[15] = 1.0;
1398 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1400 object->baseTexture.minMipLookup = minMipLookup;
1401 object->baseTexture.magLookup = magLookup;
1402 } else {
1403 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1404 object->baseTexture.magLookup = magLookup_noFilter;
1407 /* Generate all the surfaces */
1408 tmpW = Width;
1409 tmpH = Height;
1410 tmpD = Depth;
1412 for (i = 0; i < object->baseTexture.levels; i++)
1414 HRESULT hr;
1415 /* Create the volume */
1416 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1417 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1418 if(FAILED(hr)) {
1419 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1420 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1421 *ppVolumeTexture = NULL;
1422 return hr;
1425 /* Set its container to this object */
1426 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1428 /* calculate the next mipmap level */
1429 tmpW = max(1, tmpW >> 1);
1430 tmpH = max(1, tmpH >> 1);
1431 tmpD = max(1, tmpD >> 1);
1433 object->baseTexture.internal_preload = volumetexture_internal_preload;
1435 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1436 TRACE("(%p) : Created volume texture %p\n", This, object);
1437 return WINED3D_OK;
1440 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1441 UINT Width, UINT Height, UINT Depth,
1442 DWORD Usage,
1443 WINED3DFORMAT Format, WINED3DPOOL Pool,
1444 IWineD3DVolume** ppVolume,
1445 HANDLE* pSharedHandle, IUnknown *parent) {
1447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1448 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1449 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1450 HRESULT hr;
1452 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1453 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1454 return WINED3DERR_INVALIDCALL;
1457 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1458 if (!object)
1460 ERR("Out of memory\n");
1461 *ppVolume = NULL;
1462 return WINED3DERR_OUTOFVIDEOMEMORY;
1465 object->lpVtbl = &IWineD3DVolume_Vtbl;
1466 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1467 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1468 if (FAILED(hr))
1470 WARN("Failed to initialize resource, returning %#x\n", hr);
1471 HeapFree(GetProcessHeap(), 0, object);
1472 *ppVolume = NULL;
1473 return hr;
1476 TRACE("(%p) : Created resource %p\n", This, object);
1478 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1480 *ppVolume = (IWineD3DVolume *)object;
1482 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1483 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1485 object->currentDesc.Width = Width;
1486 object->currentDesc.Height = Height;
1487 object->currentDesc.Depth = Depth;
1489 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1490 object->lockable = TRUE;
1491 object->locked = FALSE;
1492 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1493 object->dirty = TRUE;
1495 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1497 return WINED3D_OK;
1500 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1501 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1502 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1505 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1506 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1507 unsigned int i, j;
1508 UINT tmpW;
1509 HRESULT hr;
1510 unsigned int pow2EdgeLength;
1512 /* TODO: It should only be possible to create textures for formats
1513 that are reported as supported */
1514 if (WINED3DFMT_UNKNOWN >= Format) {
1515 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1516 return WINED3DERR_INVALIDCALL;
1519 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1520 WARN("(%p) : Tried to create not supported cube texture\n", This);
1521 return WINED3DERR_INVALIDCALL;
1524 /* Calculate levels for mip mapping */
1525 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1527 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1529 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1530 return WINED3DERR_INVALIDCALL;
1533 if (Levels > 1)
1535 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1536 return WINED3DERR_INVALIDCALL;
1539 Levels = 1;
1541 else if (!Levels)
1543 Levels = wined3d_log2i(EdgeLength) + 1;
1544 TRACE("Calculated levels = %d\n", Levels);
1547 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1548 if (!object)
1550 ERR("Out of memory\n");
1551 *ppCubeTexture = NULL;
1552 return WINED3DERR_OUTOFVIDEOMEMORY;
1555 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1556 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1557 if (FAILED(hr))
1559 WARN("Failed to initialize resource, returning %#x\n", hr);
1560 HeapFree(GetProcessHeap(), 0, object);
1561 *ppCubeTexture = NULL;
1562 return hr;
1565 TRACE("(%p) : Created resource %p\n", This, object);
1567 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1569 basetexture_init(&object->baseTexture, Levels, Usage);
1571 TRACE("(%p) Create Cube Texture\n", This);
1573 /* Find the nearest pow2 match */
1574 pow2EdgeLength = 1;
1575 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1577 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1578 /* Precalculated scaling for 'faked' non power of two texture coords */
1579 object->baseTexture.pow2Matrix[ 0] = 1.0;
1580 object->baseTexture.pow2Matrix[ 5] = 1.0;
1581 object->baseTexture.pow2Matrix[10] = 1.0;
1582 object->baseTexture.pow2Matrix[15] = 1.0;
1583 } else {
1584 /* Precalculated scaling for 'faked' non power of two texture coords */
1585 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1586 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1587 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1588 object->baseTexture.pow2Matrix[15] = 1.0;
1589 object->baseTexture.pow2Matrix_identity = FALSE;
1592 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1594 object->baseTexture.minMipLookup = minMipLookup;
1595 object->baseTexture.magLookup = magLookup;
1596 } else {
1597 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1598 object->baseTexture.magLookup = magLookup_noFilter;
1601 /* Generate all the surfaces */
1602 tmpW = EdgeLength;
1603 for (i = 0; i < object->baseTexture.levels; i++) {
1605 /* Create the 6 faces */
1606 for (j = 0; j < 6; j++) {
1607 static const GLenum cube_targets[6] = {
1608 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1609 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1610 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1611 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1612 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1613 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1616 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1617 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1618 if (FAILED(hr))
1620 FIXME("(%p) Failed to create surface\n",object);
1621 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1622 *ppCubeTexture = NULL;
1623 return hr;
1625 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1626 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1627 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1629 tmpW = max(1, tmpW >> 1);
1631 object->baseTexture.internal_preload = cubetexture_internal_preload;
1633 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1634 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1635 return WINED3D_OK;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1641 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1642 const IWineD3DQueryVtbl *vtable;
1644 /* Just a check to see if we support this type of query */
1645 switch(Type) {
1646 case WINED3DQUERYTYPE_OCCLUSION:
1647 TRACE("(%p) occlusion query\n", This);
1648 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1649 hr = WINED3D_OK;
1650 else
1651 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1653 vtable = &IWineD3DOcclusionQuery_Vtbl;
1654 break;
1656 case WINED3DQUERYTYPE_EVENT:
1657 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1658 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1659 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1661 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1663 vtable = &IWineD3DEventQuery_Vtbl;
1664 hr = WINED3D_OK;
1665 break;
1667 case WINED3DQUERYTYPE_VCACHE:
1668 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1669 case WINED3DQUERYTYPE_VERTEXSTATS:
1670 case WINED3DQUERYTYPE_TIMESTAMP:
1671 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1672 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1673 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1674 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1675 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1676 case WINED3DQUERYTYPE_PIXELTIMINGS:
1677 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1678 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1679 default:
1680 /* Use the base Query vtable until we have a special one for each query */
1681 vtable = &IWineD3DQuery_Vtbl;
1682 FIXME("(%p) Unhandled query type %d\n", This, Type);
1684 if(NULL == ppQuery || hr != WINED3D_OK) {
1685 return hr;
1688 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1689 if(!object)
1691 ERR("Out of memory\n");
1692 *ppQuery = NULL;
1693 return WINED3DERR_OUTOFVIDEOMEMORY;
1696 object->lpVtbl = vtable;
1697 object->type = Type;
1698 object->state = QUERY_CREATED;
1699 object->wineD3DDevice = This;
1700 object->parent = parent;
1701 object->ref = 1;
1703 *ppQuery = (IWineD3DQuery *)object;
1705 /* allocated the 'extended' data based on the type of query requested */
1706 switch(Type){
1707 case WINED3DQUERYTYPE_OCCLUSION:
1708 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1709 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1711 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1712 TRACE("(%p) Allocating data for an occlusion query\n", This);
1714 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1715 ENTER_GL();
1716 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1717 LEAVE_GL();
1718 break;
1720 case WINED3DQUERYTYPE_EVENT:
1721 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1722 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1724 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1725 ENTER_GL();
1726 if(GL_SUPPORT(APPLE_FENCE)) {
1727 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1728 checkGLcall("glGenFencesAPPLE");
1729 } else if(GL_SUPPORT(NV_FENCE)) {
1730 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1731 checkGLcall("glGenFencesNV");
1733 LEAVE_GL();
1734 break;
1736 case WINED3DQUERYTYPE_VCACHE:
1737 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1738 case WINED3DQUERYTYPE_VERTEXSTATS:
1739 case WINED3DQUERYTYPE_TIMESTAMP:
1740 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1741 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1742 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1743 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1744 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1745 case WINED3DQUERYTYPE_PIXELTIMINGS:
1746 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1747 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1748 default:
1749 object->extendedData = 0;
1750 FIXME("(%p) Unhandled query type %d\n",This , Type);
1752 TRACE("(%p) : Created Query %p\n", This, object);
1753 return WINED3D_OK;
1756 /*****************************************************************************
1757 * IWineD3DDeviceImpl_SetupFullscreenWindow
1759 * Helper function that modifies a HWND's Style and ExStyle for proper
1760 * fullscreen use.
1762 * Params:
1763 * iface: Pointer to the IWineD3DDevice interface
1764 * window: Window to setup
1766 *****************************************************************************/
1767 static LONG fullscreen_style(LONG orig_style) {
1768 LONG style = orig_style;
1769 style &= ~WS_CAPTION;
1770 style &= ~WS_THICKFRAME;
1772 /* Make sure the window is managed, otherwise we won't get keyboard input */
1773 style |= WS_POPUP | WS_SYSMENU;
1775 return style;
1778 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1779 LONG exStyle = orig_exStyle;
1781 /* Filter out window decorations */
1782 exStyle &= ~WS_EX_WINDOWEDGE;
1783 exStyle &= ~WS_EX_CLIENTEDGE;
1785 return exStyle;
1788 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1791 LONG style, exStyle;
1792 /* Don't do anything if an original style is stored.
1793 * That shouldn't happen
1795 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1796 if (This->style || This->exStyle) {
1797 ERR("(%p): Want to change the window parameters of HWND %p, but "
1798 "another style is stored for restoration afterwards\n", This, window);
1801 /* Get the parameters and save them */
1802 style = GetWindowLongW(window, GWL_STYLE);
1803 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1804 This->style = style;
1805 This->exStyle = exStyle;
1807 style = fullscreen_style(style);
1808 exStyle = fullscreen_exStyle(exStyle);
1810 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1811 This->style, This->exStyle, style, exStyle);
1813 SetWindowLongW(window, GWL_STYLE, style);
1814 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1816 /* Inform the window about the update. */
1817 SetWindowPos(window, HWND_TOP, 0, 0,
1818 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1821 /*****************************************************************************
1822 * IWineD3DDeviceImpl_RestoreWindow
1824 * Helper function that restores a windows' properties when taking it out
1825 * of fullscreen mode
1827 * Params:
1828 * iface: Pointer to the IWineD3DDevice interface
1829 * window: Window to setup
1831 *****************************************************************************/
1832 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1834 LONG style, exStyle;
1836 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1837 * switch, do nothing
1839 if (!This->style && !This->exStyle) return;
1841 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1842 This, window, This->style, This->exStyle);
1844 style = GetWindowLongW(window, GWL_STYLE);
1845 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1847 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1848 * Some applications change it before calling Reset() when switching between windowed and
1849 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1851 if(style == fullscreen_style(This->style) &&
1852 exStyle == fullscreen_style(This->exStyle)) {
1853 SetWindowLongW(window, GWL_STYLE, This->style);
1854 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1857 /* Delete the old values */
1858 This->style = 0;
1859 This->exStyle = 0;
1861 /* Inform the window about the update */
1862 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1863 0, 0, 0, 0, /* Pos, Size, ignored */
1864 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1867 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1868 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1869 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1870 IUnknown *parent, WINED3DSURFTYPE surface_type)
1872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1874 HDC hDc;
1875 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1876 HRESULT hr;
1877 IUnknown *bufferParent;
1878 BOOL displaymode_set = FALSE;
1879 WINED3DDISPLAYMODE Mode;
1880 const struct GlPixelFormatDesc *format_desc;
1882 TRACE("(%p) : Created Additional Swap Chain\n", This);
1884 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1885 * does a device hold a reference to a swap chain giving them a lifetime of the device
1886 * or does the swap chain notify the device of its destruction.
1887 *******************************/
1889 /* Check the params */
1890 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1891 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1892 return WINED3DERR_INVALIDCALL;
1893 } else if (pPresentationParameters->BackBufferCount > 1) {
1894 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");
1897 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1898 if(!object)
1900 ERR("Out of memory\n");
1901 *ppSwapChain = NULL;
1902 return WINED3DERR_OUTOFVIDEOMEMORY;
1905 switch(surface_type) {
1906 case SURFACE_GDI:
1907 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1908 break;
1909 case SURFACE_OPENGL:
1910 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1911 break;
1912 case SURFACE_UNKNOWN:
1913 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1914 HeapFree(GetProcessHeap(), 0, object);
1915 return WINED3DERR_INVALIDCALL;
1917 object->wineD3DDevice = This;
1918 object->parent = parent;
1919 object->ref = 1;
1921 *ppSwapChain = (IWineD3DSwapChain *)object;
1923 /*********************
1924 * Lookup the window Handle and the relating X window handle
1925 ********************/
1927 /* Setup hwnd we are using, plus which display this equates to */
1928 object->win_handle = pPresentationParameters->hDeviceWindow;
1929 if (!object->win_handle) {
1930 object->win_handle = This->createParms.hFocusWindow;
1932 if(!pPresentationParameters->Windowed && object->win_handle) {
1933 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1934 pPresentationParameters->BackBufferWidth,
1935 pPresentationParameters->BackBufferHeight);
1938 hDc = GetDC(object->win_handle);
1939 TRACE("Using hDc %p\n", hDc);
1941 if (NULL == hDc) {
1942 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1943 return WINED3DERR_NOTAVAILABLE;
1946 /* Get info on the current display setup */
1947 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1948 object->orig_width = Mode.Width;
1949 object->orig_height = Mode.Height;
1950 object->orig_fmt = Mode.Format;
1951 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1953 if (pPresentationParameters->Windowed &&
1954 ((pPresentationParameters->BackBufferWidth == 0) ||
1955 (pPresentationParameters->BackBufferHeight == 0) ||
1956 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1958 RECT Rect;
1959 GetClientRect(object->win_handle, &Rect);
1961 if (pPresentationParameters->BackBufferWidth == 0) {
1962 pPresentationParameters->BackBufferWidth = Rect.right;
1963 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1965 if (pPresentationParameters->BackBufferHeight == 0) {
1966 pPresentationParameters->BackBufferHeight = Rect.bottom;
1967 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1969 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1970 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1971 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1975 /* Put the correct figures in the presentation parameters */
1976 TRACE("Copying across presentation parameters\n");
1977 object->presentParms = *pPresentationParameters;
1979 TRACE("calling rendertarget CB\n");
1980 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1981 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1982 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1983 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1984 if (SUCCEEDED(hr)) {
1985 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1986 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1987 if(surface_type == SURFACE_OPENGL) {
1988 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1990 } else {
1991 ERR("Failed to create the front buffer\n");
1992 goto error;
1995 /*********************
1996 * Windowed / Fullscreen
1997 *******************/
2000 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
2001 * so we should really check to see if there is a fullscreen swapchain already
2002 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
2003 **************************************/
2005 if (!pPresentationParameters->Windowed) {
2006 WINED3DDISPLAYMODE mode;
2009 /* Change the display settings */
2010 mode.Width = pPresentationParameters->BackBufferWidth;
2011 mode.Height = pPresentationParameters->BackBufferHeight;
2012 mode.Format = pPresentationParameters->BackBufferFormat;
2013 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
2015 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
2016 displaymode_set = TRUE;
2020 * Create an opengl context for the display visual
2021 * NOTE: the visual is chosen as the window is created and the glcontext cannot
2022 * use different properties after that point in time. FIXME: How to handle when requested format
2023 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
2024 * it chooses is identical to the one already being used!
2025 **********************************/
2026 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
2028 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
2029 if(!object->context) {
2030 ERR("Failed to create the context array\n");
2031 hr = E_OUTOFMEMORY;
2032 goto error;
2034 object->num_contexts = 1;
2036 if(surface_type == SURFACE_OPENGL) {
2037 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
2038 if (!object->context[0]) {
2039 ERR("Failed to create a new context\n");
2040 hr = WINED3DERR_NOTAVAILABLE;
2041 goto error;
2042 } else {
2043 TRACE("Context created (HWND=%p, glContext=%p)\n",
2044 object->win_handle, object->context[0]->glCtx);
2048 /*********************
2049 * Create the back, front and stencil buffers
2050 *******************/
2051 if(object->presentParms.BackBufferCount > 0) {
2052 UINT i;
2054 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2055 if(!object->backBuffer) {
2056 ERR("Out of memory\n");
2057 hr = E_OUTOFMEMORY;
2058 goto error;
2061 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2062 TRACE("calling rendertarget CB\n");
2063 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2064 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2065 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2066 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2067 if(SUCCEEDED(hr)) {
2068 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2069 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2070 } else {
2071 ERR("Cannot create new back buffer\n");
2072 goto error;
2074 if(surface_type == SURFACE_OPENGL) {
2075 ENTER_GL();
2076 glDrawBuffer(GL_BACK);
2077 checkGLcall("glDrawBuffer(GL_BACK)");
2078 LEAVE_GL();
2081 } else {
2082 object->backBuffer = NULL;
2084 /* Single buffering - draw to front buffer */
2085 if(surface_type == SURFACE_OPENGL) {
2086 ENTER_GL();
2087 glDrawBuffer(GL_FRONT);
2088 checkGLcall("glDrawBuffer(GL_FRONT)");
2089 LEAVE_GL();
2093 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2094 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2095 TRACE("Creating depth stencil buffer\n");
2096 if (This->auto_depth_stencil_buffer == NULL ) {
2097 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2098 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2099 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2100 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2101 &This->auto_depth_stencil_buffer);
2102 if (SUCCEEDED(hr)) {
2103 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2104 } else {
2105 ERR("Failed to create the auto depth stencil\n");
2106 goto error;
2111 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2113 TRACE("Created swapchain %p\n", object);
2114 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2115 return WINED3D_OK;
2117 error:
2118 if (displaymode_set) {
2119 DEVMODEW devmode;
2120 RECT clip_rc;
2122 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2123 ClipCursor(NULL);
2125 /* Change the display settings */
2126 memset(&devmode, 0, sizeof(devmode));
2127 devmode.dmSize = sizeof(devmode);
2128 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2129 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2130 devmode.dmPelsWidth = object->orig_width;
2131 devmode.dmPelsHeight = object->orig_height;
2132 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2135 if (object->backBuffer) {
2136 UINT i;
2137 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2138 if(object->backBuffer[i]) {
2139 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2140 IUnknown_Release(bufferParent); /* once for the get parent */
2141 if (IUnknown_Release(bufferParent) > 0) {
2142 FIXME("(%p) Something's still holding the back buffer\n",This);
2146 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2147 object->backBuffer = NULL;
2149 if(object->context && object->context[0])
2150 DestroyContext(This, object->context[0]);
2151 if(object->frontBuffer) {
2152 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2153 IUnknown_Release(bufferParent); /* once for the get parent */
2154 if (IUnknown_Release(bufferParent) > 0) {
2155 FIXME("(%p) Something's still holding the front buffer\n",This);
2158 HeapFree(GetProcessHeap(), 0, object);
2159 return hr;
2162 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2163 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2165 TRACE("(%p)\n", This);
2167 return This->NumberOfSwapChains;
2170 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2172 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2174 if(iSwapChain < This->NumberOfSwapChains) {
2175 *pSwapChain = This->swapchains[iSwapChain];
2176 IWineD3DSwapChain_AddRef(*pSwapChain);
2177 TRACE("(%p) returning %p\n", This, *pSwapChain);
2178 return WINED3D_OK;
2179 } else {
2180 TRACE("Swapchain out of range\n");
2181 *pSwapChain = NULL;
2182 return WINED3DERR_INVALIDCALL;
2186 /*****
2187 * Vertex Declaration
2188 *****/
2189 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2190 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2192 IWineD3DVertexDeclarationImpl *object = NULL;
2193 HRESULT hr = WINED3D_OK;
2195 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2196 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2198 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2199 if(!object)
2201 ERR("Out of memory\n");
2202 *ppVertexDeclaration = NULL;
2203 return WINED3DERR_OUTOFVIDEOMEMORY;
2206 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2207 object->wineD3DDevice = This;
2208 object->parent = parent;
2209 object->ref = 1;
2211 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2213 hr = vertexdeclaration_init(object, elements, element_count);
2215 if(FAILED(hr)) {
2216 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2217 *ppVertexDeclaration = NULL;
2220 return hr;
2223 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2224 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2226 unsigned int idx, idx2;
2227 unsigned int offset;
2228 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2229 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2230 BOOL has_blend_idx = has_blend &&
2231 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2232 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2233 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2234 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2235 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2236 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2237 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2239 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2240 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2241 WINED3DVERTEXELEMENT *elements = NULL;
2243 unsigned int size;
2244 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2245 if (has_blend_idx) num_blends--;
2247 /* Compute declaration size */
2248 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2249 has_psize + has_diffuse + has_specular + num_textures;
2251 /* convert the declaration */
2252 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2253 if (!elements) return ~0U;
2255 idx = 0;
2256 if (has_pos) {
2257 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2258 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2259 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2261 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2262 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2263 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2265 else {
2266 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2267 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2269 elements[idx].usage_idx = 0;
2270 idx++;
2272 if (has_blend && (num_blends > 0)) {
2273 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2274 elements[idx].format = WINED3DFMT_A8R8G8B8;
2275 else {
2276 switch(num_blends) {
2277 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2278 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2279 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2280 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2281 default:
2282 ERR("Unexpected amount of blend values: %u\n", num_blends);
2285 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2286 elements[idx].usage_idx = 0;
2287 idx++;
2289 if (has_blend_idx) {
2290 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2291 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2292 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2293 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2294 elements[idx].format = WINED3DFMT_A8R8G8B8;
2295 else
2296 elements[idx].format = WINED3DFMT_R32_FLOAT;
2297 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2298 elements[idx].usage_idx = 0;
2299 idx++;
2301 if (has_normal) {
2302 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2303 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2304 elements[idx].usage_idx = 0;
2305 idx++;
2307 if (has_psize) {
2308 elements[idx].format = WINED3DFMT_R32_FLOAT;
2309 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2310 elements[idx].usage_idx = 0;
2311 idx++;
2313 if (has_diffuse) {
2314 elements[idx].format = WINED3DFMT_A8R8G8B8;
2315 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2316 elements[idx].usage_idx = 0;
2317 idx++;
2319 if (has_specular) {
2320 elements[idx].format = WINED3DFMT_A8R8G8B8;
2321 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2322 elements[idx].usage_idx = 1;
2323 idx++;
2325 for (idx2 = 0; idx2 < num_textures; idx2++) {
2326 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2327 switch (numcoords) {
2328 case WINED3DFVF_TEXTUREFORMAT1:
2329 elements[idx].format = WINED3DFMT_R32_FLOAT;
2330 break;
2331 case WINED3DFVF_TEXTUREFORMAT2:
2332 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2333 break;
2334 case WINED3DFVF_TEXTUREFORMAT3:
2335 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2336 break;
2337 case WINED3DFVF_TEXTUREFORMAT4:
2338 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2339 break;
2341 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2342 elements[idx].usage_idx = idx2;
2343 idx++;
2346 /* Now compute offsets, and initialize the rest of the fields */
2347 for (idx = 0, offset = 0; idx < size; ++idx)
2349 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2350 elements[idx].input_slot = 0;
2351 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2352 elements[idx].offset = offset;
2353 offset += format_desc->component_count * format_desc->component_size;
2356 *ppVertexElements = elements;
2357 return size;
2360 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2361 WINED3DVERTEXELEMENT* elements = NULL;
2362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2363 unsigned int size;
2364 DWORD hr;
2366 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2367 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2369 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2370 HeapFree(GetProcessHeap(), 0, elements);
2371 if (hr != S_OK) return hr;
2373 return WINED3D_OK;
2376 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2378 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2379 HRESULT hr = WINED3D_OK;
2381 if (!pFunction) return WINED3DERR_INVALIDCALL;
2383 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2384 if (!object)
2386 ERR("Out of memory\n");
2387 *ppVertexShader = NULL;
2388 return WINED3DERR_OUTOFVIDEOMEMORY;
2391 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2392 object->parent = parent;
2393 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2394 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2395 *ppVertexShader = (IWineD3DVertexShader *)object;
2397 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2399 if (vertex_declaration) {
2400 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2403 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2404 if (FAILED(hr))
2406 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2407 IWineD3DVertexShader_Release(*ppVertexShader);
2408 *ppVertexShader = NULL;
2409 return hr;
2412 return hr;
2415 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2417 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2418 HRESULT hr = WINED3D_OK;
2420 if (!pFunction) return WINED3DERR_INVALIDCALL;
2422 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2423 if (!object)
2425 ERR("Out of memory\n");
2426 *ppPixelShader = NULL;
2427 return WINED3DERR_OUTOFVIDEOMEMORY;
2430 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2431 object->parent = parent;
2432 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2433 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2434 *ppPixelShader = (IWineD3DPixelShader *)object;
2436 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2438 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2439 if (FAILED(hr))
2441 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2442 IWineD3DPixelShader_Release(*ppPixelShader);
2443 *ppPixelShader = NULL;
2444 return hr;
2447 return hr;
2450 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2451 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2454 IWineD3DPaletteImpl *object;
2455 HRESULT hr;
2456 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2458 /* Create the new object */
2459 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2460 if(!object) {
2461 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2462 return E_OUTOFMEMORY;
2465 object->lpVtbl = &IWineD3DPalette_Vtbl;
2466 object->ref = 1;
2467 object->Flags = Flags;
2468 object->parent = Parent;
2469 object->wineD3DDevice = This;
2470 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2471 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2473 if(!object->hpal) {
2474 HeapFree( GetProcessHeap(), 0, object);
2475 return E_OUTOFMEMORY;
2478 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2479 if(FAILED(hr)) {
2480 IWineD3DPalette_Release((IWineD3DPalette *) object);
2481 return hr;
2484 *Palette = (IWineD3DPalette *) object;
2486 return WINED3D_OK;
2489 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2490 HBITMAP hbm;
2491 BITMAP bm;
2492 HRESULT hr;
2493 HDC dcb = NULL, dcs = NULL;
2494 WINEDDCOLORKEY colorkey;
2496 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2497 if(hbm)
2499 GetObjectA(hbm, sizeof(BITMAP), &bm);
2500 dcb = CreateCompatibleDC(NULL);
2501 if(!dcb) goto out;
2502 SelectObject(dcb, hbm);
2504 else
2506 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2507 * couldn't be loaded
2509 memset(&bm, 0, sizeof(bm));
2510 bm.bmWidth = 32;
2511 bm.bmHeight = 32;
2514 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2515 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2516 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2517 if(FAILED(hr)) {
2518 ERR("Wine logo requested, but failed to create surface\n");
2519 goto out;
2522 if(dcb) {
2523 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2524 if(FAILED(hr)) goto out;
2525 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2526 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2528 colorkey.dwColorSpaceLowValue = 0;
2529 colorkey.dwColorSpaceHighValue = 0;
2530 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2531 } else {
2532 /* Fill the surface with a white color to show that wined3d is there */
2533 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2536 out:
2537 if(dcb) {
2538 DeleteDC(dcb);
2540 if(hbm) {
2541 DeleteObject(hbm);
2543 return;
2546 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2547 unsigned int i;
2548 /* Under DirectX you can have texture stage operations even if no texture is
2549 bound, whereas opengl will only do texture operations when a valid texture is
2550 bound. We emulate this by creating dummy textures and binding them to each
2551 texture stage, but disable all stages by default. Hence if a stage is enabled
2552 then the default texture will kick in until replaced by a SetTexture call */
2553 ENTER_GL();
2555 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2556 /* The dummy texture does not have client storage backing */
2557 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2558 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2560 for (i = 0; i < GL_LIMITS(textures); i++) {
2561 GLubyte white = 255;
2563 /* Make appropriate texture active */
2564 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2565 checkGLcall("glActiveTextureARB");
2567 /* Generate an opengl texture name */
2568 glGenTextures(1, &This->dummyTextureName[i]);
2569 checkGLcall("glGenTextures");
2570 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2572 /* Generate a dummy 2d texture (not using 1d because they cause many
2573 * DRI drivers fall back to sw) */
2574 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2575 checkGLcall("glBindTexture");
2577 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2578 checkGLcall("glTexImage2D");
2580 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2581 /* Reenable because if supported it is enabled by default */
2582 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2583 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2586 LEAVE_GL();
2589 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2590 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2593 IWineD3DSwapChainImpl *swapchain = NULL;
2594 HRESULT hr;
2595 DWORD state;
2596 unsigned int i;
2598 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2600 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2601 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2603 /* TODO: Test if OpenGL is compiled in and loaded */
2605 TRACE("(%p) : Creating stateblock\n", This);
2606 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2607 hr = IWineD3DDevice_CreateStateBlock(iface,
2608 WINED3DSBT_INIT,
2609 (IWineD3DStateBlock **)&This->stateBlock,
2610 NULL);
2611 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2612 WARN("Failed to create stateblock\n");
2613 goto err_out;
2615 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2616 This->updateStateBlock = This->stateBlock;
2617 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2619 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2620 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2622 This->NumberOfPalettes = 1;
2623 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2624 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2625 ERR("Out of memory!\n");
2626 goto err_out;
2628 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2629 if(!This->palettes[0]) {
2630 ERR("Out of memory!\n");
2631 goto err_out;
2633 for (i = 0; i < 256; ++i) {
2634 This->palettes[0][i].peRed = 0xFF;
2635 This->palettes[0][i].peGreen = 0xFF;
2636 This->palettes[0][i].peBlue = 0xFF;
2637 This->palettes[0][i].peFlags = 0xFF;
2639 This->currentPalette = 0;
2641 /* Initialize the texture unit mapping to a 1:1 mapping */
2642 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2643 if (state < GL_LIMITS(fragment_samplers)) {
2644 This->texUnitMap[state] = state;
2645 This->rev_tex_unit_map[state] = state;
2646 } else {
2647 This->texUnitMap[state] = -1;
2648 This->rev_tex_unit_map[state] = -1;
2652 /* Setup the implicit swapchain */
2653 TRACE("Creating implicit swapchain\n");
2654 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2655 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2656 if (FAILED(hr))
2658 WARN("Failed to create implicit swapchain\n");
2659 goto err_out;
2662 This->NumberOfSwapChains = 1;
2663 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2664 if(!This->swapchains) {
2665 ERR("Out of memory!\n");
2666 goto err_out;
2668 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2670 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2671 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2672 This->render_targets[0] = swapchain->backBuffer[0];
2673 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2675 else {
2676 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2677 This->render_targets[0] = swapchain->frontBuffer;
2678 This->lastActiveRenderTarget = swapchain->frontBuffer;
2680 IWineD3DSurface_AddRef(This->render_targets[0]);
2681 This->activeContext = swapchain->context[0];
2682 This->lastThread = GetCurrentThreadId();
2684 /* Depth Stencil support */
2685 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2686 if (NULL != This->stencilBufferTarget) {
2687 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2690 hr = This->shader_backend->shader_alloc_private(iface);
2691 if(FAILED(hr)) {
2692 TRACE("Shader private data couldn't be allocated\n");
2693 goto err_out;
2695 hr = This->frag_pipe->alloc_private(iface);
2696 if(FAILED(hr)) {
2697 TRACE("Fragment pipeline private data couldn't be allocated\n");
2698 goto err_out;
2700 hr = This->blitter->alloc_private(iface);
2701 if(FAILED(hr)) {
2702 TRACE("Blitter private data couldn't be allocated\n");
2703 goto err_out;
2706 /* Set up some starting GL setup */
2708 /* Setup all the devices defaults */
2709 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2710 create_dummy_textures(This);
2712 ENTER_GL();
2714 /* Initialize the current view state */
2715 This->view_ident = 1;
2716 This->contexts[0]->last_was_rhw = 0;
2717 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2718 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2720 switch(wined3d_settings.offscreen_rendering_mode) {
2721 case ORM_FBO:
2722 case ORM_PBUFFER:
2723 This->offscreenBuffer = GL_BACK;
2724 break;
2726 case ORM_BACKBUFFER:
2728 if(This->activeContext->aux_buffers > 0) {
2729 TRACE("Using auxilliary buffer for offscreen rendering\n");
2730 This->offscreenBuffer = GL_AUX0;
2731 } else {
2732 TRACE("Using back buffer for offscreen rendering\n");
2733 This->offscreenBuffer = GL_BACK;
2738 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2739 LEAVE_GL();
2741 /* Clear the screen */
2742 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2743 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2744 0x00, 1.0, 0);
2746 This->d3d_initialized = TRUE;
2748 if(wined3d_settings.logo) {
2749 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2751 This->highest_dirty_ps_const = 0;
2752 This->highest_dirty_vs_const = 0;
2753 return WINED3D_OK;
2755 err_out:
2756 HeapFree(GetProcessHeap(), 0, This->render_targets);
2757 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2758 HeapFree(GetProcessHeap(), 0, This->swapchains);
2759 This->NumberOfSwapChains = 0;
2760 if(This->palettes) {
2761 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2762 HeapFree(GetProcessHeap(), 0, This->palettes);
2764 This->NumberOfPalettes = 0;
2765 if(swapchain) {
2766 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2768 if(This->stateBlock) {
2769 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2770 This->stateBlock = NULL;
2772 if (This->blit_priv) {
2773 This->blitter->free_private(iface);
2775 if (This->fragment_priv) {
2776 This->frag_pipe->free_private(iface);
2778 if (This->shader_priv) {
2779 This->shader_backend->shader_free_private(iface);
2781 return hr;
2784 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2785 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2788 IWineD3DSwapChainImpl *swapchain = NULL;
2789 HRESULT hr;
2791 /* Setup the implicit swapchain */
2792 TRACE("Creating implicit swapchain\n");
2793 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2794 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2795 if (FAILED(hr))
2797 WARN("Failed to create implicit swapchain\n");
2798 goto err_out;
2801 This->NumberOfSwapChains = 1;
2802 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2803 if(!This->swapchains) {
2804 ERR("Out of memory!\n");
2805 goto err_out;
2807 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2808 return WINED3D_OK;
2810 err_out:
2811 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2812 return hr;
2815 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2817 IWineD3DResource_UnLoad(resource);
2818 IWineD3DResource_Release(resource);
2819 return WINED3D_OK;
2822 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2824 int sampler;
2825 UINT i;
2826 TRACE("(%p)\n", This);
2828 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2830 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2831 * it was created. Thus make sure a context is active for the glDelete* calls
2833 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2835 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2837 /* Unload resources */
2838 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2840 TRACE("Deleting high order patches\n");
2841 for(i = 0; i < PATCHMAP_SIZE; i++) {
2842 struct list *e1, *e2;
2843 struct WineD3DRectPatch *patch;
2844 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2845 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2846 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2850 /* Delete the palette conversion shader if it is around */
2851 if(This->paletteConversionShader) {
2852 ENTER_GL();
2853 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2854 LEAVE_GL();
2855 This->paletteConversionShader = 0;
2858 /* Delete the pbuffer context if there is any */
2859 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2861 /* Delete the mouse cursor texture */
2862 if(This->cursorTexture) {
2863 ENTER_GL();
2864 glDeleteTextures(1, &This->cursorTexture);
2865 LEAVE_GL();
2866 This->cursorTexture = 0;
2869 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2870 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2872 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2873 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2876 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2877 * private data, it might contain opengl pointers
2879 if(This->depth_blt_texture) {
2880 glDeleteTextures(1, &This->depth_blt_texture);
2881 This->depth_blt_texture = 0;
2883 if (This->depth_blt_rb) {
2884 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2885 This->depth_blt_rb = 0;
2886 This->depth_blt_rb_w = 0;
2887 This->depth_blt_rb_h = 0;
2890 /* Release the update stateblock */
2891 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2892 if(This->updateStateBlock != This->stateBlock)
2893 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2895 This->updateStateBlock = NULL;
2897 { /* because were not doing proper internal refcounts releasing the primary state block
2898 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2899 to set this->stateBlock = NULL; first */
2900 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2901 This->stateBlock = NULL;
2903 /* Release the stateblock */
2904 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2905 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2909 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2910 This->blitter->free_private(iface);
2911 This->frag_pipe->free_private(iface);
2912 This->shader_backend->shader_free_private(iface);
2914 /* Release the buffers (with sanity checks)*/
2915 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2916 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2917 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2918 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2920 This->stencilBufferTarget = NULL;
2922 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2923 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2924 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2926 TRACE("Setting rendertarget to NULL\n");
2927 This->render_targets[0] = NULL;
2929 if (This->auto_depth_stencil_buffer) {
2930 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2931 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2933 This->auto_depth_stencil_buffer = NULL;
2936 for(i=0; i < This->NumberOfSwapChains; i++) {
2937 TRACE("Releasing the implicit swapchain %d\n", i);
2938 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2939 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2943 HeapFree(GetProcessHeap(), 0, This->swapchains);
2944 This->swapchains = NULL;
2945 This->NumberOfSwapChains = 0;
2947 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2948 HeapFree(GetProcessHeap(), 0, This->palettes);
2949 This->palettes = NULL;
2950 This->NumberOfPalettes = 0;
2952 HeapFree(GetProcessHeap(), 0, This->render_targets);
2953 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2954 This->render_targets = NULL;
2955 This->draw_buffers = NULL;
2957 This->d3d_initialized = FALSE;
2958 return WINED3D_OK;
2961 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2963 unsigned int i;
2965 for(i=0; i < This->NumberOfSwapChains; i++) {
2966 TRACE("Releasing the implicit swapchain %d\n", i);
2967 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2968 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2972 HeapFree(GetProcessHeap(), 0, This->swapchains);
2973 This->swapchains = NULL;
2974 This->NumberOfSwapChains = 0;
2975 return WINED3D_OK;
2978 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2979 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2980 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2982 * There is no way to deactivate thread safety once it is enabled.
2984 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2987 /*For now just store the flag(needed in case of ddraw) */
2988 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2990 return;
2993 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2994 const WINED3DDISPLAYMODE* pMode) {
2995 DEVMODEW devmode;
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 LONG ret;
2998 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2999 RECT clip_rc;
3001 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
3003 /* Resize the screen even without a window:
3004 * The app could have unset it with SetCooperativeLevel, but not called
3005 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
3006 * but we don't have any hwnd
3009 memset(&devmode, 0, sizeof(devmode));
3010 devmode.dmSize = sizeof(devmode);
3011 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
3012 devmode.dmBitsPerPel = format_desc->byte_count * 8;
3013 devmode.dmPelsWidth = pMode->Width;
3014 devmode.dmPelsHeight = pMode->Height;
3016 devmode.dmDisplayFrequency = pMode->RefreshRate;
3017 if (pMode->RefreshRate != 0) {
3018 devmode.dmFields |= DM_DISPLAYFREQUENCY;
3021 /* Only change the mode if necessary */
3022 if( (This->ddraw_width == pMode->Width) &&
3023 (This->ddraw_height == pMode->Height) &&
3024 (This->ddraw_format == pMode->Format) &&
3025 (pMode->RefreshRate == 0) ) {
3026 return WINED3D_OK;
3029 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
3030 if (ret != DISP_CHANGE_SUCCESSFUL) {
3031 if(devmode.dmDisplayFrequency != 0) {
3032 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
3033 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
3034 devmode.dmDisplayFrequency = 0;
3035 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
3037 if(ret != DISP_CHANGE_SUCCESSFUL) {
3038 return WINED3DERR_NOTAVAILABLE;
3042 /* Store the new values */
3043 This->ddraw_width = pMode->Width;
3044 This->ddraw_height = pMode->Height;
3045 This->ddraw_format = pMode->Format;
3047 /* And finally clip mouse to our screen */
3048 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3049 ClipCursor(&clip_rc);
3051 return WINED3D_OK;
3054 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 *ppD3D= This->wineD3D;
3057 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3058 IWineD3D_AddRef(*ppD3D);
3059 return WINED3D_OK;
3062 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3066 (This->adapter->TextureRam/(1024*1024)),
3067 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3068 /* return simulated texture memory left */
3069 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3072 /*****
3073 * Get / Set Stream Source
3074 *****/
3075 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3076 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 IWineD3DBuffer *oldSrc;
3081 if (StreamNumber >= MAX_STREAMS) {
3082 WARN("Stream out of range %d\n", StreamNumber);
3083 return WINED3DERR_INVALIDCALL;
3084 } else if(OffsetInBytes & 0x3) {
3085 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3086 return WINED3DERR_INVALIDCALL;
3089 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3090 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3092 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3094 if(oldSrc == pStreamData &&
3095 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3096 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3097 TRACE("Application is setting the old values over, nothing to do\n");
3098 return WINED3D_OK;
3101 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3102 if (pStreamData) {
3103 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3104 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3107 /* Handle recording of state blocks */
3108 if (This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3110 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3111 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3112 return WINED3D_OK;
3115 if (pStreamData != NULL) {
3116 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3117 IWineD3DBuffer_AddRef(pStreamData);
3119 if (oldSrc != NULL) {
3120 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3121 IWineD3DBuffer_Release(oldSrc);
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3130 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3135 This->stateBlock->streamSource[StreamNumber],
3136 This->stateBlock->streamOffset[StreamNumber],
3137 This->stateBlock->streamStride[StreamNumber]);
3139 if (StreamNumber >= MAX_STREAMS) {
3140 WARN("Stream out of range %d\n", StreamNumber);
3141 return WINED3DERR_INVALIDCALL;
3143 *pStream = This->stateBlock->streamSource[StreamNumber];
3144 *pStride = This->stateBlock->streamStride[StreamNumber];
3145 if (pOffset) {
3146 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3149 if (*pStream != NULL) {
3150 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3152 return WINED3D_OK;
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3158 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3160 /* Verify input at least in d3d9 this is invalid*/
3161 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3162 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3163 return WINED3DERR_INVALIDCALL;
3165 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3166 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3167 return WINED3DERR_INVALIDCALL;
3169 if( Divider == 0 ){
3170 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3171 return WINED3DERR_INVALIDCALL;
3174 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3175 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3177 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3178 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3180 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3181 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3192 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3194 TRACE("(%p) : returning %d\n", This, *Divider);
3196 return WINED3D_OK;
3199 /*****
3200 * Get / Set & Multiply Transform
3201 *****/
3202 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 /* Most of this routine, comments included copied from ddraw tree initially: */
3206 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3208 /* Handle recording of state blocks */
3209 if (This->isRecordingState) {
3210 TRACE("Recording... not performing anything\n");
3211 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3212 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3213 return WINED3D_OK;
3217 * If the new matrix is the same as the current one,
3218 * we cut off any further processing. this seems to be a reasonable
3219 * optimization because as was noticed, some apps (warcraft3 for example)
3220 * tend towards setting the same matrix repeatedly for some reason.
3222 * From here on we assume that the new matrix is different, wherever it matters.
3224 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3225 TRACE("The app is setting the same matrix over again\n");
3226 return WINED3D_OK;
3227 } else {
3228 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3232 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3233 where ViewMat = Camera space, WorldMat = world space.
3235 In OpenGL, camera and world space is combined into GL_MODELVIEW
3236 matrix. The Projection matrix stay projection matrix.
3239 /* Capture the times we can just ignore the change for now */
3240 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3241 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3242 /* Handled by the state manager */
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3246 return WINED3D_OK;
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3252 *pMatrix = This->stateBlock->transforms[State];
3253 return WINED3D_OK;
3256 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3257 const WINED3DMATRIX *mat = NULL;
3258 WINED3DMATRIX temp;
3260 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3261 * below means it will be recorded in a state block change, but it
3262 * works regardless where it is recorded.
3263 * If this is found to be wrong, change to StateBlock.
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3266 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3268 if (State <= HIGHEST_TRANSFORMSTATE)
3270 mat = &This->updateStateBlock->transforms[State];
3271 } else {
3272 FIXME("Unhandled transform state!!\n");
3275 multiply_matrix(&temp, mat, pMatrix);
3277 /* Apply change via set transform - will reapply to eg. lights this way */
3278 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3281 /*****
3282 * Get / Set Light
3283 *****/
3284 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3285 you can reference any indexes you want as long as that number max are enabled at any
3286 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3287 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3288 but when recording, just build a chain pretty much of commands to be replayed. */
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3291 float rho;
3292 PLIGHTINFOEL *object = NULL;
3293 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3294 struct list *e;
3296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3299 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3300 * the gl driver.
3302 if(!pLight) {
3303 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3304 return WINED3DERR_INVALIDCALL;
3307 switch(pLight->Type) {
3308 case WINED3DLIGHT_POINT:
3309 case WINED3DLIGHT_SPOT:
3310 case WINED3DLIGHT_PARALLELPOINT:
3311 case WINED3DLIGHT_GLSPOT:
3312 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3313 * most wanted
3315 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3316 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3317 return WINED3DERR_INVALIDCALL;
3319 break;
3321 case WINED3DLIGHT_DIRECTIONAL:
3322 /* Ignores attenuation */
3323 break;
3325 default:
3326 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3327 return WINED3DERR_INVALIDCALL;
3330 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3331 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3332 if(object->OriginalIndex == Index) break;
3333 object = NULL;
3336 if(!object) {
3337 TRACE("Adding new light\n");
3338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3339 if(!object) {
3340 ERR("Out of memory error when allocating a light\n");
3341 return E_OUTOFMEMORY;
3343 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3344 object->glIndex = -1;
3345 object->OriginalIndex = Index;
3346 object->changed = TRUE;
3349 /* Initialize the object */
3350 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,
3351 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3352 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3353 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3354 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3355 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3356 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3358 /* Save away the information */
3359 object->OriginalParms = *pLight;
3361 switch (pLight->Type) {
3362 case WINED3DLIGHT_POINT:
3363 /* Position */
3364 object->lightPosn[0] = pLight->Position.x;
3365 object->lightPosn[1] = pLight->Position.y;
3366 object->lightPosn[2] = pLight->Position.z;
3367 object->lightPosn[3] = 1.0f;
3368 object->cutoff = 180.0f;
3369 /* FIXME: Range */
3370 break;
3372 case WINED3DLIGHT_DIRECTIONAL:
3373 /* Direction */
3374 object->lightPosn[0] = -pLight->Direction.x;
3375 object->lightPosn[1] = -pLight->Direction.y;
3376 object->lightPosn[2] = -pLight->Direction.z;
3377 object->lightPosn[3] = 0.0;
3378 object->exponent = 0.0f;
3379 object->cutoff = 180.0f;
3380 break;
3382 case WINED3DLIGHT_SPOT:
3383 /* Position */
3384 object->lightPosn[0] = pLight->Position.x;
3385 object->lightPosn[1] = pLight->Position.y;
3386 object->lightPosn[2] = pLight->Position.z;
3387 object->lightPosn[3] = 1.0;
3389 /* Direction */
3390 object->lightDirn[0] = pLight->Direction.x;
3391 object->lightDirn[1] = pLight->Direction.y;
3392 object->lightDirn[2] = pLight->Direction.z;
3393 object->lightDirn[3] = 1.0;
3396 * opengl-ish and d3d-ish spot lights use too different models for the
3397 * light "intensity" as a function of the angle towards the main light direction,
3398 * so we only can approximate very roughly.
3399 * however spot lights are rather rarely used in games (if ever used at all).
3400 * furthermore if still used, probably nobody pays attention to such details.
3402 if (pLight->Falloff == 0) {
3403 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3404 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3405 * will always be 1.0 for both of them, and we don't have to care for the
3406 * rest of the rather complex calculation
3408 object->exponent = 0;
3409 } else {
3410 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3411 if (rho < 0.0001) rho = 0.0001f;
3412 object->exponent = -0.3/log(cos(rho/2));
3414 if (object->exponent > 128.0) {
3415 object->exponent = 128.0;
3417 object->cutoff = pLight->Phi*90/M_PI;
3419 /* FIXME: Range */
3420 break;
3422 default:
3423 FIXME("Unrecognized light type %d\n", pLight->Type);
3426 /* Update the live definitions if the light is currently assigned a glIndex */
3427 if (object->glIndex != -1 && !This->isRecordingState) {
3428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3434 PLIGHTINFOEL *lightInfo = NULL;
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3437 struct list *e;
3438 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3440 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3441 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3442 if(lightInfo->OriginalIndex == Index) break;
3443 lightInfo = NULL;
3446 if (lightInfo == NULL) {
3447 TRACE("Light information requested but light not defined\n");
3448 return WINED3DERR_INVALIDCALL;
3451 *pLight = lightInfo->OriginalParms;
3452 return WINED3D_OK;
3455 /*****
3456 * Get / Set Light Enable
3457 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3458 *****/
3459 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3460 PLIGHTINFOEL *lightInfo = NULL;
3461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3463 struct list *e;
3464 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3466 /* Tests show true = 128...not clear why */
3467 Enable = Enable? 128: 0;
3469 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3470 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3471 if(lightInfo->OriginalIndex == Index) break;
3472 lightInfo = NULL;
3474 TRACE("Found light: %p\n", lightInfo);
3476 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3477 if (lightInfo == NULL) {
3479 TRACE("Light enabled requested but light not defined, so defining one!\n");
3480 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3482 /* Search for it again! Should be fairly quick as near head of list */
3483 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3484 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3485 if(lightInfo->OriginalIndex == Index) break;
3486 lightInfo = NULL;
3488 if (lightInfo == NULL) {
3489 FIXME("Adding default lights has failed dismally\n");
3490 return WINED3DERR_INVALIDCALL;
3494 lightInfo->enabledChanged = TRUE;
3495 if(!Enable) {
3496 if(lightInfo->glIndex != -1) {
3497 if(!This->isRecordingState) {
3498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3501 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3502 lightInfo->glIndex = -1;
3503 } else {
3504 TRACE("Light already disabled, nothing to do\n");
3506 lightInfo->enabled = FALSE;
3507 } else {
3508 lightInfo->enabled = TRUE;
3509 if (lightInfo->glIndex != -1) {
3510 /* nop */
3511 TRACE("Nothing to do as light was enabled\n");
3512 } else {
3513 int i;
3514 /* Find a free gl light */
3515 for(i = 0; i < This->maxConcurrentLights; i++) {
3516 if(This->updateStateBlock->activeLights[i] == NULL) {
3517 This->updateStateBlock->activeLights[i] = lightInfo;
3518 lightInfo->glIndex = i;
3519 break;
3522 if(lightInfo->glIndex == -1) {
3523 /* Our tests show that Windows returns D3D_OK in this situation, even with
3524 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3525 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3526 * as well for those lights.
3528 * TODO: Test how this affects rendering
3530 WARN("Too many concurrently active lights\n");
3531 return WINED3D_OK;
3534 /* i == lightInfo->glIndex */
3535 if(!This->isRecordingState) {
3536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3541 return WINED3D_OK;
3544 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3546 PLIGHTINFOEL *lightInfo = NULL;
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 struct list *e;
3549 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3550 TRACE("(%p) : for idx(%d)\n", This, Index);
3552 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3553 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3554 if(lightInfo->OriginalIndex == Index) break;
3555 lightInfo = NULL;
3558 if (lightInfo == NULL) {
3559 TRACE("Light enabled state requested but light not defined\n");
3560 return WINED3DERR_INVALIDCALL;
3562 /* true is 128 according to SetLightEnable */
3563 *pEnable = lightInfo->enabled ? 128 : 0;
3564 return WINED3D_OK;
3567 /*****
3568 * Get / Set Clip Planes
3569 *****/
3570 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3572 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3574 /* Validate Index */
3575 if (Index >= GL_LIMITS(clipplanes)) {
3576 TRACE("Application has requested clipplane this device doesn't support\n");
3577 return WINED3DERR_INVALIDCALL;
3580 This->updateStateBlock->changed.clipplane |= 1 << Index;
3582 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3583 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3584 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3585 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3586 TRACE("Application is setting old values over, nothing to do\n");
3587 return WINED3D_OK;
3590 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3591 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3592 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3593 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3595 /* Handle recording of state blocks */
3596 if (This->isRecordingState) {
3597 TRACE("Recording... not performing anything\n");
3598 return WINED3D_OK;
3601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3603 return WINED3D_OK;
3606 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 TRACE("(%p) : for idx %d\n", This, Index);
3610 /* Validate Index */
3611 if (Index >= GL_LIMITS(clipplanes)) {
3612 TRACE("Application has requested clipplane this device doesn't support\n");
3613 return WINED3DERR_INVALIDCALL;
3616 pPlane[0] = This->stateBlock->clipplane[Index][0];
3617 pPlane[1] = This->stateBlock->clipplane[Index][1];
3618 pPlane[2] = This->stateBlock->clipplane[Index][2];
3619 pPlane[3] = This->stateBlock->clipplane[Index][3];
3620 return WINED3D_OK;
3623 /*****
3624 * Get / Set Clip Plane Status
3625 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3626 *****/
3627 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 FIXME("(%p) : stub\n", This);
3630 if (NULL == pClipStatus) {
3631 return WINED3DERR_INVALIDCALL;
3633 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3634 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3635 return WINED3D_OK;
3638 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 FIXME("(%p) : stub\n", This);
3641 if (NULL == pClipStatus) {
3642 return WINED3DERR_INVALIDCALL;
3644 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3645 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3646 return WINED3D_OK;
3649 /*****
3650 * Get / Set Material
3651 *****/
3652 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655 This->updateStateBlock->changed.material = TRUE;
3656 This->updateStateBlock->material = *pMaterial;
3658 /* Handle recording of state blocks */
3659 if (This->isRecordingState) {
3660 TRACE("Recording... not performing anything\n");
3661 return WINED3D_OK;
3664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3665 return WINED3D_OK;
3668 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3670 *pMaterial = This->updateStateBlock->material;
3671 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3672 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3673 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3674 pMaterial->Ambient.b, pMaterial->Ambient.a);
3675 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3676 pMaterial->Specular.b, pMaterial->Specular.a);
3677 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3678 pMaterial->Emissive.b, pMaterial->Emissive.a);
3679 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3681 return WINED3D_OK;
3684 /*****
3685 * Get / Set Indices
3686 *****/
3687 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3689 IWineD3DIndexBuffer *oldIdxs;
3691 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3692 oldIdxs = This->updateStateBlock->pIndexData;
3694 This->updateStateBlock->changed.indices = TRUE;
3695 This->updateStateBlock->pIndexData = pIndexData;
3697 /* Handle recording of state blocks */
3698 if (This->isRecordingState) {
3699 TRACE("Recording... not performing anything\n");
3700 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3701 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3702 return WINED3D_OK;
3705 if(oldIdxs != pIndexData) {
3706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3707 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3708 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3710 return WINED3D_OK;
3713 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3716 *ppIndexData = This->stateBlock->pIndexData;
3718 /* up ref count on ppindexdata */
3719 if (*ppIndexData) {
3720 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3721 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3722 }else{
3723 TRACE("(%p) No index data set\n", This);
3725 TRACE("Returning %p\n", *ppIndexData);
3727 return WINED3D_OK;
3730 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3731 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3733 TRACE("(%p)->(%d)\n", This, BaseIndex);
3735 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3736 TRACE("Application is setting the old value over, nothing to do\n");
3737 return WINED3D_OK;
3740 This->updateStateBlock->baseVertexIndex = BaseIndex;
3742 if (This->isRecordingState) {
3743 TRACE("Recording... not performing anything\n");
3744 return WINED3D_OK;
3746 /* The base vertex index affects the stream sources */
3747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3748 return WINED3D_OK;
3751 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 TRACE("(%p) : base_index %p\n", This, base_index);
3755 *base_index = This->stateBlock->baseVertexIndex;
3757 TRACE("Returning %u\n", *base_index);
3759 return WINED3D_OK;
3762 /*****
3763 * Get / Set Viewports
3764 *****/
3765 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3768 TRACE("(%p)\n", This);
3769 This->updateStateBlock->changed.viewport = TRUE;
3770 This->updateStateBlock->viewport = *pViewport;
3772 /* Handle recording of state blocks */
3773 if (This->isRecordingState) {
3774 TRACE("Recording... not performing anything\n");
3775 return WINED3D_OK;
3778 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3779 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3782 return WINED3D_OK;
3786 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 TRACE("(%p)\n", This);
3789 *pViewport = This->stateBlock->viewport;
3790 return WINED3D_OK;
3793 /*****
3794 * Get / Set Render States
3795 * TODO: Verify against dx9 definitions
3796 *****/
3797 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3800 DWORD oldValue = This->stateBlock->renderState[State];
3802 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3804 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3805 This->updateStateBlock->renderState[State] = Value;
3807 /* Handle recording of state blocks */
3808 if (This->isRecordingState) {
3809 TRACE("Recording... not performing anything\n");
3810 return WINED3D_OK;
3813 /* Compared here and not before the assignment to allow proper stateblock recording */
3814 if(Value == oldValue) {
3815 TRACE("Application is setting the old value over, nothing to do\n");
3816 } else {
3817 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3820 return WINED3D_OK;
3823 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3825 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3826 *pValue = This->stateBlock->renderState[State];
3827 return WINED3D_OK;
3830 /*****
3831 * Get / Set Sampler States
3832 * TODO: Verify against dx9 definitions
3833 *****/
3835 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3837 DWORD oldValue;
3839 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3840 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3842 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3843 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3846 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3847 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3848 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3851 * SetSampler is designed to allow for more than the standard up to 8 textures
3852 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3853 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3855 * http://developer.nvidia.com/object/General_FAQ.html#t6
3857 * There are two new settings for GForce
3858 * the sampler one:
3859 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3860 * and the texture one:
3861 * GL_MAX_TEXTURE_COORDS_ARB.
3862 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3863 ******************/
3865 oldValue = This->stateBlock->samplerState[Sampler][Type];
3866 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3867 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3869 /* Handle recording of state blocks */
3870 if (This->isRecordingState) {
3871 TRACE("Recording... not performing anything\n");
3872 return WINED3D_OK;
3875 if(oldValue == Value) {
3876 TRACE("Application is setting the old value over, nothing to do\n");
3877 return WINED3D_OK;
3880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3882 return WINED3D_OK;
3885 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3888 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3889 This, Sampler, debug_d3dsamplerstate(Type), Type);
3891 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3892 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3895 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3896 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3897 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3899 *Value = This->stateBlock->samplerState[Sampler][Type];
3900 TRACE("(%p) : Returning %#x\n", This, *Value);
3902 return WINED3D_OK;
3905 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3908 This->updateStateBlock->changed.scissorRect = TRUE;
3909 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3910 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3911 return WINED3D_OK;
3913 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3915 if(This->isRecordingState) {
3916 TRACE("Recording... not performing anything\n");
3917 return WINED3D_OK;
3920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3922 return WINED3D_OK;
3925 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 *pRect = This->updateStateBlock->scissorRect;
3929 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3930 return WINED3D_OK;
3933 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3935 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3937 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3939 This->updateStateBlock->vertexDecl = pDecl;
3940 This->updateStateBlock->changed.vertexDecl = TRUE;
3942 if (This->isRecordingState) {
3943 TRACE("Recording... not performing anything\n");
3944 return WINED3D_OK;
3945 } else if(pDecl == oldDecl) {
3946 /* Checked after the assignment to allow proper stateblock recording */
3947 TRACE("Application is setting the old declaration over, nothing to do\n");
3948 return WINED3D_OK;
3951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3952 return WINED3D_OK;
3955 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3960 *ppDecl = This->stateBlock->vertexDecl;
3961 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3962 return WINED3D_OK;
3965 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3967 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3969 This->updateStateBlock->vertexShader = pShader;
3970 This->updateStateBlock->changed.vertexShader = TRUE;
3972 if (This->isRecordingState) {
3973 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3974 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3975 TRACE("Recording... not performing anything\n");
3976 return WINED3D_OK;
3977 } else if(oldShader == pShader) {
3978 /* Checked here to allow proper stateblock recording */
3979 TRACE("App is setting the old shader over, nothing to do\n");
3980 return WINED3D_OK;
3983 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3984 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3985 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3989 return WINED3D_OK;
3992 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 if (NULL == ppShader) {
3996 return WINED3DERR_INVALIDCALL;
3998 *ppShader = This->stateBlock->vertexShader;
3999 if( NULL != *ppShader)
4000 IWineD3DVertexShader_AddRef(*ppShader);
4002 TRACE("(%p) : returning %p\n", This, *ppShader);
4003 return WINED3D_OK;
4006 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4007 IWineD3DDevice *iface,
4008 UINT start,
4009 CONST BOOL *srcData,
4010 UINT count) {
4012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4013 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4015 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4016 iface, srcData, start, count);
4018 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4020 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4021 for (i = 0; i < cnt; i++)
4022 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4024 for (i = start; i < cnt + start; ++i) {
4025 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
4028 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4030 return WINED3D_OK;
4033 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4034 IWineD3DDevice *iface,
4035 UINT start,
4036 BOOL *dstData,
4037 UINT count) {
4039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4040 int cnt = min(count, MAX_CONST_B - start);
4042 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4043 iface, dstData, start, count);
4045 if (dstData == NULL || cnt < 0)
4046 return WINED3DERR_INVALIDCALL;
4048 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4049 return WINED3D_OK;
4052 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4053 IWineD3DDevice *iface,
4054 UINT start,
4055 CONST int *srcData,
4056 UINT count) {
4058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4059 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4061 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4062 iface, srcData, start, count);
4064 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4066 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4067 for (i = 0; i < cnt; i++)
4068 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4069 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4071 for (i = start; i < cnt + start; ++i) {
4072 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4075 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4077 return WINED3D_OK;
4080 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4081 IWineD3DDevice *iface,
4082 UINT start,
4083 int *dstData,
4084 UINT count) {
4086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4087 int cnt = min(count, MAX_CONST_I - start);
4089 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4090 iface, dstData, start, count);
4092 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4093 return WINED3DERR_INVALIDCALL;
4095 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4096 return WINED3D_OK;
4099 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4100 IWineD3DDevice *iface,
4101 UINT start,
4102 CONST float *srcData,
4103 UINT count) {
4105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 UINT i;
4108 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4109 iface, srcData, start, count);
4111 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4112 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
4113 return WINED3DERR_INVALIDCALL;
4115 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4116 if(TRACE_ON(d3d)) {
4117 for (i = 0; i < count; i++)
4118 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4119 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4122 if (!This->isRecordingState)
4124 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4128 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4129 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4131 return WINED3D_OK;
4134 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4135 IWineD3DDevice *iface,
4136 UINT start,
4137 float *dstData,
4138 UINT count) {
4140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4141 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4143 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4144 iface, dstData, start, count);
4146 if (dstData == NULL || cnt < 0)
4147 return WINED3DERR_INVALIDCALL;
4149 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4150 return WINED3D_OK;
4153 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4154 DWORD i;
4155 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4161 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4162 int i = This->rev_tex_unit_map[unit];
4163 int j = This->texUnitMap[stage];
4165 This->texUnitMap[stage] = unit;
4166 if (i != -1 && i != stage) {
4167 This->texUnitMap[i] = -1;
4170 This->rev_tex_unit_map[unit] = stage;
4171 if (j != -1 && j != unit) {
4172 This->rev_tex_unit_map[j] = -1;
4176 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4177 int i;
4179 This->fixed_function_usage_map = 0;
4180 for (i = 0; i < MAX_TEXTURES; ++i) {
4181 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4182 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4183 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4184 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4185 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4186 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4187 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4188 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4190 if (color_op == WINED3DTOP_DISABLE) {
4191 /* Not used, and disable higher stages */
4192 break;
4195 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4196 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4197 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4198 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4199 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4200 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4201 This->fixed_function_usage_map |= (1 << i);
4204 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4205 This->fixed_function_usage_map |= (1 << (i + 1));
4210 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4211 unsigned int i, tex;
4212 WORD ffu_map;
4214 device_update_fixed_function_usage_map(This);
4215 ffu_map = This->fixed_function_usage_map;
4217 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4218 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4219 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4221 if (!(ffu_map & 1)) continue;
4223 if (This->texUnitMap[i] != i) {
4224 device_map_stage(This, i, i);
4225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4226 markTextureStagesDirty(This, i);
4229 return;
4232 /* Now work out the mapping */
4233 tex = 0;
4234 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4236 if (!(ffu_map & 1)) continue;
4238 if (This->texUnitMap[i] != tex) {
4239 device_map_stage(This, i, tex);
4240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4241 markTextureStagesDirty(This, i);
4244 ++tex;
4248 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4249 const DWORD *sampler_tokens =
4250 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4251 unsigned int i;
4253 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4254 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4255 device_map_stage(This, i, i);
4256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4257 if (i < MAX_TEXTURES) {
4258 markTextureStagesDirty(This, i);
4264 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4265 const DWORD *vshader_sampler_tokens, int unit)
4267 int current_mapping = This->rev_tex_unit_map[unit];
4269 if (current_mapping == -1) {
4270 /* Not currently used */
4271 return TRUE;
4274 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4275 /* Used by a fragment sampler */
4277 if (!pshader_sampler_tokens) {
4278 /* No pixel shader, check fixed function */
4279 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4282 /* Pixel shader, check the shader's sampler map */
4283 return !pshader_sampler_tokens[current_mapping];
4286 /* Used by a vertex sampler */
4287 return !vshader_sampler_tokens[current_mapping];
4290 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4291 const DWORD *vshader_sampler_tokens =
4292 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4293 const DWORD *pshader_sampler_tokens = NULL;
4294 int start = GL_LIMITS(combined_samplers) - 1;
4295 int i;
4297 if (ps) {
4298 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4300 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4301 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4302 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4305 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4306 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4307 if (vshader_sampler_tokens[i]) {
4308 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4310 /* Already mapped somewhere */
4311 continue;
4314 while (start >= 0) {
4315 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4316 device_map_stage(This, vsampler_idx, start);
4317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4319 --start;
4320 break;
4323 --start;
4329 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4330 BOOL vs = use_vs(This->stateBlock);
4331 BOOL ps = use_ps(This->stateBlock);
4333 * Rules are:
4334 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4335 * that would be really messy and require shader recompilation
4336 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4337 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4339 if (ps) {
4340 device_map_psamplers(This);
4341 } else {
4342 device_map_fixed_function_samplers(This);
4345 if (vs) {
4346 device_map_vsamplers(This, ps);
4350 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4352 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4353 This->updateStateBlock->pixelShader = pShader;
4354 This->updateStateBlock->changed.pixelShader = TRUE;
4356 /* Handle recording of state blocks */
4357 if (This->isRecordingState) {
4358 TRACE("Recording... not performing anything\n");
4361 if (This->isRecordingState) {
4362 TRACE("Recording... not performing anything\n");
4363 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4364 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4365 return WINED3D_OK;
4368 if(pShader == oldShader) {
4369 TRACE("App is setting the old pixel shader over, nothing to do\n");
4370 return WINED3D_OK;
4373 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4374 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4376 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4379 return WINED3D_OK;
4382 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4385 if (NULL == ppShader) {
4386 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4387 return WINED3DERR_INVALIDCALL;
4390 *ppShader = This->stateBlock->pixelShader;
4391 if (NULL != *ppShader) {
4392 IWineD3DPixelShader_AddRef(*ppShader);
4394 TRACE("(%p) : returning %p\n", This, *ppShader);
4395 return WINED3D_OK;
4398 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4399 IWineD3DDevice *iface,
4400 UINT start,
4401 CONST BOOL *srcData,
4402 UINT count) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4407 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4408 iface, srcData, start, count);
4410 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4412 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4413 for (i = 0; i < cnt; i++)
4414 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4416 for (i = start; i < cnt + start; ++i) {
4417 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4420 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4422 return WINED3D_OK;
4425 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4426 IWineD3DDevice *iface,
4427 UINT start,
4428 BOOL *dstData,
4429 UINT count) {
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 int cnt = min(count, MAX_CONST_B - start);
4434 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4435 iface, dstData, start, count);
4437 if (dstData == NULL || cnt < 0)
4438 return WINED3DERR_INVALIDCALL;
4440 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4441 return WINED3D_OK;
4444 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4445 IWineD3DDevice *iface,
4446 UINT start,
4447 CONST int *srcData,
4448 UINT count) {
4450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4453 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4454 iface, srcData, start, count);
4456 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4458 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4459 for (i = 0; i < cnt; i++)
4460 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4461 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4463 for (i = start; i < cnt + start; ++i) {
4464 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4467 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4469 return WINED3D_OK;
4472 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4473 IWineD3DDevice *iface,
4474 UINT start,
4475 int *dstData,
4476 UINT count) {
4478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4479 int cnt = min(count, MAX_CONST_I - start);
4481 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4482 iface, dstData, start, count);
4484 if (dstData == NULL || cnt < 0)
4485 return WINED3DERR_INVALIDCALL;
4487 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4488 return WINED3D_OK;
4491 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4492 IWineD3DDevice *iface,
4493 UINT start,
4494 CONST float *srcData,
4495 UINT count) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 UINT i;
4500 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4501 iface, srcData, start, count);
4503 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4504 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4505 return WINED3DERR_INVALIDCALL;
4507 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4508 if(TRACE_ON(d3d)) {
4509 for (i = 0; i < count; i++)
4510 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4511 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4514 if (!This->isRecordingState)
4516 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4520 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4521 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4523 return WINED3D_OK;
4526 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4527 IWineD3DDevice *iface,
4528 UINT start,
4529 float *dstData,
4530 UINT count) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4533 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4535 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4536 iface, dstData, start, count);
4538 if (dstData == NULL || cnt < 0)
4539 return WINED3DERR_INVALIDCALL;
4541 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4542 return WINED3D_OK;
4545 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4546 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4547 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags)
4549 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4550 unsigned int i;
4551 DWORD DestFVF = dest->fvf;
4552 WINED3DVIEWPORT vp;
4553 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4554 BOOL doClip;
4555 DWORD numTextures;
4557 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4559 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4562 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4564 ERR("Source has no position mask\n");
4565 return WINED3DERR_INVALIDCALL;
4568 /* We might access VBOs from this code, so hold the lock */
4569 ENTER_GL();
4571 if (dest->resource.allocatedMemory == NULL) {
4572 /* This may happen if we do direct locking into a vbo. Unlikely,
4573 * but theoretically possible(ddraw processvertices test)
4575 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4576 if(!dest->resource.allocatedMemory) {
4577 LEAVE_GL();
4578 ERR("Out of memory\n");
4579 return E_OUTOFMEMORY;
4581 if (dest->buffer_object)
4583 const void *src;
4584 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4585 checkGLcall("glBindBufferARB");
4586 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4587 if(src) {
4588 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4590 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4591 checkGLcall("glUnmapBufferARB");
4595 /* Get a pointer into the destination vbo(create one if none exists) and
4596 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4598 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4600 dest->flags |= WINED3D_BUFFER_CREATEBO;
4601 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4604 if (dest->buffer_object)
4606 unsigned char extrabytes = 0;
4607 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4608 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4609 * this may write 4 extra bytes beyond the area that should be written
4611 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4612 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4613 if(!dest_conv_addr) {
4614 ERR("Out of memory\n");
4615 /* Continue without storing converted vertices */
4617 dest_conv = dest_conv_addr;
4620 /* Should I clip?
4621 * a) WINED3DRS_CLIPPING is enabled
4622 * b) WINED3DVOP_CLIP is passed
4624 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4625 static BOOL warned = FALSE;
4627 * The clipping code is not quite correct. Some things need
4628 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4629 * so disable clipping for now.
4630 * (The graphics in Half-Life are broken, and my processvertices
4631 * test crashes with IDirect3DDevice3)
4632 doClip = TRUE;
4634 doClip = FALSE;
4635 if(!warned) {
4636 warned = TRUE;
4637 FIXME("Clipping is broken and disabled for now\n");
4639 } else doClip = FALSE;
4640 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4642 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4643 WINED3DTS_VIEW,
4644 &view_mat);
4645 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4646 WINED3DTS_PROJECTION,
4647 &proj_mat);
4648 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4649 WINED3DTS_WORLDMATRIX(0),
4650 &world_mat);
4652 TRACE("View mat:\n");
4653 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);
4654 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);
4655 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);
4656 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);
4658 TRACE("Proj mat:\n");
4659 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);
4660 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);
4661 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);
4662 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);
4664 TRACE("World mat:\n");
4665 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);
4666 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);
4667 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);
4668 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);
4670 /* Get the viewport */
4671 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4672 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4673 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4675 multiply_matrix(&mat,&view_mat,&world_mat);
4676 multiply_matrix(&mat,&proj_mat,&mat);
4678 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4680 for (i = 0; i < dwCount; i+= 1) {
4681 unsigned int tex_index;
4683 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4684 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4685 /* The position first */
4686 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4687 const float *p = (const float *)(element->data + i * element->stride);
4688 float x, y, z, rhw;
4689 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4691 /* Multiplication with world, view and projection matrix */
4692 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);
4693 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);
4694 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);
4695 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);
4697 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4699 /* WARNING: The following things are taken from d3d7 and were not yet checked
4700 * against d3d8 or d3d9!
4703 /* Clipping conditions: From msdn
4705 * A vertex is clipped if it does not match the following requirements
4706 * -rhw < x <= rhw
4707 * -rhw < y <= rhw
4708 * 0 < z <= rhw
4709 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4711 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4712 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4716 if( !doClip ||
4717 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4718 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4719 ( rhw > eps ) ) ) {
4721 /* "Normal" viewport transformation (not clipped)
4722 * 1) The values are divided by rhw
4723 * 2) The y axis is negative, so multiply it with -1
4724 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4725 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4726 * 4) Multiply x with Width/2 and add Width/2
4727 * 5) The same for the height
4728 * 6) Add the viewpoint X and Y to the 2D coordinates and
4729 * The minimum Z value to z
4730 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4732 * Well, basically it's simply a linear transformation into viewport
4733 * coordinates
4736 x /= rhw;
4737 y /= rhw;
4738 z /= rhw;
4740 y *= -1;
4742 x *= vp.Width / 2;
4743 y *= vp.Height / 2;
4744 z *= vp.MaxZ - vp.MinZ;
4746 x += vp.Width / 2 + vp.X;
4747 y += vp.Height / 2 + vp.Y;
4748 z += vp.MinZ;
4750 rhw = 1 / rhw;
4751 } else {
4752 /* That vertex got clipped
4753 * Contrary to OpenGL it is not dropped completely, it just
4754 * undergoes a different calculation.
4756 TRACE("Vertex got clipped\n");
4757 x += rhw;
4758 y += rhw;
4760 x /= 2;
4761 y /= 2;
4763 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4764 * outside of the main vertex buffer memory. That needs some more
4765 * investigation...
4769 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4772 ( (float *) dest_ptr)[0] = x;
4773 ( (float *) dest_ptr)[1] = y;
4774 ( (float *) dest_ptr)[2] = z;
4775 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4777 dest_ptr += 3 * sizeof(float);
4779 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4780 dest_ptr += sizeof(float);
4783 if(dest_conv) {
4784 float w = 1 / rhw;
4785 ( (float *) dest_conv)[0] = x * w;
4786 ( (float *) dest_conv)[1] = y * w;
4787 ( (float *) dest_conv)[2] = z * w;
4788 ( (float *) dest_conv)[3] = w;
4790 dest_conv += 3 * sizeof(float);
4792 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4793 dest_conv += sizeof(float);
4797 if (DestFVF & WINED3DFVF_PSIZE) {
4798 dest_ptr += sizeof(DWORD);
4799 if(dest_conv) dest_conv += sizeof(DWORD);
4801 if (DestFVF & WINED3DFVF_NORMAL) {
4802 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4803 const float *normal = (const float *)(element->data + i * element->stride);
4804 /* AFAIK this should go into the lighting information */
4805 FIXME("Didn't expect the destination to have a normal\n");
4806 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4807 if(dest_conv) {
4808 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4812 if (DestFVF & WINED3DFVF_DIFFUSE) {
4813 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4814 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4815 if(!color_d) {
4816 static BOOL warned = FALSE;
4818 if(!warned) {
4819 ERR("No diffuse color in source, but destination has one\n");
4820 warned = TRUE;
4823 *( (DWORD *) dest_ptr) = 0xffffffff;
4824 dest_ptr += sizeof(DWORD);
4826 if(dest_conv) {
4827 *( (DWORD *) dest_conv) = 0xffffffff;
4828 dest_conv += sizeof(DWORD);
4831 else {
4832 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4833 if(dest_conv) {
4834 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4835 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4836 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4837 dest_conv += sizeof(DWORD);
4842 if (DestFVF & WINED3DFVF_SPECULAR) {
4843 /* What's the color value in the feedback buffer? */
4844 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4845 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4846 if(!color_s) {
4847 static BOOL warned = FALSE;
4849 if(!warned) {
4850 ERR("No specular color in source, but destination has one\n");
4851 warned = TRUE;
4854 *( (DWORD *) dest_ptr) = 0xFF000000;
4855 dest_ptr += sizeof(DWORD);
4857 if(dest_conv) {
4858 *( (DWORD *) dest_conv) = 0xFF000000;
4859 dest_conv += sizeof(DWORD);
4862 else {
4863 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4864 if(dest_conv) {
4865 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4866 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4867 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4868 dest_conv += sizeof(DWORD);
4873 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4874 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4875 const float *tex_coord = (const float *)(element->data + i * element->stride);
4876 if(!tex_coord) {
4877 ERR("No source texture, but destination requests one\n");
4878 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4879 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4881 else {
4882 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4883 if(dest_conv) {
4884 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4890 if(dest_conv) {
4891 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4892 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4893 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4894 dwCount * get_flexible_vertex_size(DestFVF),
4895 dest_conv_addr));
4896 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4897 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4900 LEAVE_GL();
4902 return WINED3D_OK;
4904 #undef copy_and_next
4906 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4907 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4910 struct wined3d_stream_info stream_info;
4911 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4912 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4914 if(pVertexDecl) {
4915 ERR("Output vertex declaration not implemented yet\n");
4918 /* Need any context to write to the vbo. */
4919 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4921 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4922 * control the streamIsUP flag, thus restore it afterwards.
4924 This->stateBlock->streamIsUP = FALSE;
4925 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4926 This->stateBlock->streamIsUP = streamWasUP;
4928 if(vbo || SrcStartIndex) {
4929 unsigned int i;
4930 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4931 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4933 * Also get the start index in, but only loop over all elements if there's something to add at all.
4935 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4937 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4938 if (e->buffer_object)
4940 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4941 e->buffer_object = 0;
4942 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)vb->resource.allocatedMemory);
4943 ENTER_GL();
4944 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4945 vb->buffer_object = 0;
4946 LEAVE_GL();
4948 if (e->data) e->data += e->stride * SrcStartIndex;
4952 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4953 (struct wined3d_buffer *)pDestBuffer, Flags);
4956 /*****
4957 * Get / Set Texture Stage States
4958 * TODO: Verify against dx9 definitions
4959 *****/
4960 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4964 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4966 if (Stage >= MAX_TEXTURES) {
4967 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4968 return WINED3D_OK;
4971 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4972 This->updateStateBlock->textureState[Stage][Type] = Value;
4974 if (This->isRecordingState) {
4975 TRACE("Recording... not performing anything\n");
4976 return WINED3D_OK;
4979 /* Checked after the assignments to allow proper stateblock recording */
4980 if(oldValue == Value) {
4981 TRACE("App is setting the old value over, nothing to do\n");
4982 return WINED3D_OK;
4985 if(Stage > This->stateBlock->lowest_disabled_stage &&
4986 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4987 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4988 * Changes in other states are important on disabled stages too
4990 return WINED3D_OK;
4993 if(Type == WINED3DTSS_COLOROP) {
4994 unsigned int i;
4996 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4997 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4998 * they have to be disabled
5000 * The current stage is dirtified below.
5002 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
5003 TRACE("Additionally dirtifying stage %u\n", i);
5004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
5006 This->stateBlock->lowest_disabled_stage = Stage;
5007 TRACE("New lowest disabled: %u\n", Stage);
5008 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
5009 /* Previously disabled stage enabled. Stages above it may need enabling
5010 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
5011 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
5013 * Again stage Stage doesn't need to be dirtified here, it is handled below.
5016 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
5017 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
5018 break;
5020 TRACE("Additionally dirtifying stage %u due to enable\n", i);
5021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
5023 This->stateBlock->lowest_disabled_stage = i;
5024 TRACE("New lowest disabled: %u\n", i);
5028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
5030 return WINED3D_OK;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5035 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5036 *pValue = This->updateStateBlock->textureState[Stage][Type];
5037 return WINED3D_OK;
5040 /*****
5041 * Get / Set Texture
5042 *****/
5043 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5045 IWineD3DBaseTexture *oldTexture;
5047 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
5049 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5050 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5053 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5054 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5055 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5058 oldTexture = This->updateStateBlock->textures[Stage];
5060 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5061 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5063 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5064 return WINED3DERR_INVALIDCALL;
5067 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5068 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5070 This->updateStateBlock->changed.textures |= 1 << Stage;
5071 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5072 This->updateStateBlock->textures[Stage] = pTexture;
5074 /* Handle recording of state blocks */
5075 if (This->isRecordingState) {
5076 TRACE("Recording... not performing anything\n");
5077 return WINED3D_OK;
5080 if(oldTexture == pTexture) {
5081 TRACE("App is setting the same texture again, nothing to do\n");
5082 return WINED3D_OK;
5085 /** NOTE: MSDN says that setTexture increases the reference count,
5086 * and that the application must set the texture back to null (or have a leaky application),
5087 * This means we should pass the refcount up to the parent
5088 *******************************/
5089 if (NULL != This->updateStateBlock->textures[Stage]) {
5090 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5091 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5092 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5094 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5096 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5101 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5102 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5103 * so the COLOROP and ALPHAOP have to be dirtified.
5105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5108 if(bindCount == 1) {
5109 new->baseTexture.sampler = Stage;
5111 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5115 if (NULL != oldTexture) {
5116 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5117 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5119 IWineD3DBaseTexture_Release(oldTexture);
5120 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5125 if(bindCount && old->baseTexture.sampler == Stage) {
5126 int i;
5127 /* Have to do a search for the other sampler(s) where the texture is bound to
5128 * Shouldn't happen as long as apps bind a texture only to one stage
5130 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5131 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5132 if(This->updateStateBlock->textures[i] == oldTexture) {
5133 old->baseTexture.sampler = i;
5134 break;
5140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5142 return WINED3D_OK;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5150 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5151 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5154 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5155 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5156 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5159 *ppTexture=This->stateBlock->textures[Stage];
5160 if (*ppTexture)
5161 IWineD3DBaseTexture_AddRef(*ppTexture);
5163 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5165 return WINED3D_OK;
5168 /*****
5169 * Get Back Buffer
5170 *****/
5171 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5172 IWineD3DSurface **ppBackBuffer) {
5173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5174 IWineD3DSwapChain *swapChain;
5175 HRESULT hr;
5177 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5179 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5180 if (hr == WINED3D_OK) {
5181 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5182 IWineD3DSwapChain_Release(swapChain);
5183 } else {
5184 *ppBackBuffer = NULL;
5186 return hr;
5189 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 WARN("(%p) : stub, calling idirect3d for now\n", This);
5192 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5195 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5197 IWineD3DSwapChain *swapChain;
5198 HRESULT hr;
5200 if(iSwapChain > 0) {
5201 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5202 if (hr == WINED3D_OK) {
5203 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5204 IWineD3DSwapChain_Release(swapChain);
5205 } else {
5206 FIXME("(%p) Error getting display mode\n", This);
5208 } else {
5209 /* Don't read the real display mode,
5210 but return the stored mode instead. X11 can't change the color
5211 depth, and some apps are pretty angry if they SetDisplayMode from
5212 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5214 Also don't relay to the swapchain because with ddraw it's possible
5215 that there isn't a swapchain at all */
5216 pMode->Width = This->ddraw_width;
5217 pMode->Height = This->ddraw_height;
5218 pMode->Format = This->ddraw_format;
5219 pMode->RefreshRate = 0;
5220 hr = WINED3D_OK;
5223 return hr;
5226 /*****
5227 * Stateblock related functions
5228 *****/
5230 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 IWineD3DStateBlock *stateblock;
5233 HRESULT hr;
5235 TRACE("(%p)\n", This);
5237 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5239 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5240 if (FAILED(hr)) return hr;
5242 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5243 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5244 This->isRecordingState = TRUE;
5246 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5248 return WINED3D_OK;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 unsigned int i, j;
5254 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5256 if (!This->isRecordingState) {
5257 WARN("(%p) not recording! returning error\n", This);
5258 *ppStateBlock = NULL;
5259 return WINED3DERR_INVALIDCALL;
5262 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5264 DWORD map = object->changed.renderState[i];
5265 for (j = 0; map; map >>= 1, ++j)
5267 if (!(map & 1)) continue;
5269 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5273 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5275 DWORD map = object->changed.transform[i];
5276 for (j = 0; map; map >>= 1, ++j)
5278 if (!(map & 1)) continue;
5280 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5283 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5284 if(object->changed.vertexShaderConstantsF[i]) {
5285 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5286 object->num_contained_vs_consts_f++;
5289 for(i = 0; i < MAX_CONST_I; i++) {
5290 if (object->changed.vertexShaderConstantsI & (1 << i))
5292 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5293 object->num_contained_vs_consts_i++;
5296 for(i = 0; i < MAX_CONST_B; i++) {
5297 if (object->changed.vertexShaderConstantsB & (1 << i))
5299 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5300 object->num_contained_vs_consts_b++;
5303 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5305 if (object->changed.pixelShaderConstantsF[i])
5307 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5308 ++object->num_contained_ps_consts_f;
5311 for(i = 0; i < MAX_CONST_I; i++) {
5312 if (object->changed.pixelShaderConstantsI & (1 << i))
5314 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5315 object->num_contained_ps_consts_i++;
5318 for(i = 0; i < MAX_CONST_B; i++) {
5319 if (object->changed.pixelShaderConstantsB & (1 << i))
5321 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5322 object->num_contained_ps_consts_b++;
5325 for(i = 0; i < MAX_TEXTURES; i++) {
5326 DWORD map = object->changed.textureState[i];
5328 for(j = 0; map; map >>= 1, ++j)
5330 if (!(map & 1)) continue;
5332 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5333 object->contained_tss_states[object->num_contained_tss_states].state = j;
5334 ++object->num_contained_tss_states;
5337 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5338 DWORD map = object->changed.samplerState[i];
5340 for (j = 0; map; map >>= 1, ++j)
5342 if (!(map & 1)) continue;
5344 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5345 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5346 ++object->num_contained_sampler_states;
5350 *ppStateBlock = (IWineD3DStateBlock*) object;
5351 This->isRecordingState = FALSE;
5352 This->updateStateBlock = This->stateBlock;
5353 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5354 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5355 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5356 return WINED3D_OK;
5359 /*****
5360 * Scene related functions
5361 *****/
5362 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5363 /* At the moment we have no need for any functionality at the beginning
5364 of a scene */
5365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5366 TRACE("(%p)\n", This);
5368 if(This->inScene) {
5369 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5370 return WINED3DERR_INVALIDCALL;
5372 This->inScene = TRUE;
5373 return WINED3D_OK;
5376 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 TRACE("(%p)\n", This);
5380 if(!This->inScene) {
5381 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5382 return WINED3DERR_INVALIDCALL;
5385 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5386 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5387 glFlush();
5388 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5389 * fails
5392 This->inScene = FALSE;
5393 return WINED3D_OK;
5396 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5397 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5398 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5400 IWineD3DSwapChain *swapChain = NULL;
5401 int i;
5402 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5404 TRACE("(%p) Presenting the frame\n", This);
5406 for(i = 0 ; i < swapchains ; i ++) {
5408 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5409 TRACE("presentinng chain %d, %p\n", i, swapChain);
5410 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5411 IWineD3DSwapChain_Release(swapChain);
5414 return WINED3D_OK;
5417 /* Not called from the VTable (internal subroutine) */
5418 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5419 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5420 float Z, DWORD Stencil) {
5421 GLbitfield glMask = 0;
5422 unsigned int i;
5423 WINED3DRECT curRect;
5424 RECT vp_rect;
5425 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5426 UINT drawable_width, drawable_height;
5427 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5428 IWineD3DSwapChainImpl *swapchain = NULL;
5430 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5431 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5432 * for the cleared parts, and the untouched parts.
5434 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5435 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5436 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5437 * checking all this if the dest surface is in the drawable anyway.
5439 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5440 while(1) {
5441 if(vp->X != 0 || vp->Y != 0 ||
5442 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5443 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5444 break;
5446 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5447 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5448 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5449 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5450 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5451 break;
5453 if(Count > 0 && pRects && (
5454 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5455 pRects[0].x2 < target->currentDesc.Width ||
5456 pRects[0].y2 < target->currentDesc.Height)) {
5457 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5458 break;
5460 break;
5464 target->get_drawable_size(target, &drawable_width, &drawable_height);
5466 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5467 ENTER_GL();
5469 /* Only set the values up once, as they are not changing */
5470 if (Flags & WINED3DCLEAR_STENCIL) {
5471 glClearStencil(Stencil);
5472 checkGLcall("glClearStencil");
5473 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5474 glStencilMask(0xFFFFFFFF);
5477 if (Flags & WINED3DCLEAR_ZBUFFER) {
5478 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5479 glDepthMask(GL_TRUE);
5480 glClearDepth(Z);
5481 checkGLcall("glClearDepth");
5482 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5485 if (vp->X != 0 || vp->Y != 0 ||
5486 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5487 surface_load_ds_location(This->stencilBufferTarget, location);
5489 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5490 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5491 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5492 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5493 surface_load_ds_location(This->stencilBufferTarget, location);
5495 else if (Count > 0 && pRects && (
5496 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5497 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5498 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5499 surface_load_ds_location(This->stencilBufferTarget, location);
5503 if (Flags & WINED3DCLEAR_TARGET) {
5504 TRACE("Clearing screen with glClear to color %x\n", Color);
5505 glClearColor(D3DCOLOR_R(Color),
5506 D3DCOLOR_G(Color),
5507 D3DCOLOR_B(Color),
5508 D3DCOLOR_A(Color));
5509 checkGLcall("glClearColor");
5511 /* Clear ALL colors! */
5512 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5513 glMask = glMask | GL_COLOR_BUFFER_BIT;
5516 vp_rect.left = vp->X;
5517 vp_rect.top = vp->Y;
5518 vp_rect.right = vp->X + vp->Width;
5519 vp_rect.bottom = vp->Y + vp->Height;
5520 if (!(Count > 0 && pRects)) {
5521 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5522 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5524 if(This->render_offscreen) {
5525 glScissor(vp_rect.left, vp_rect.top,
5526 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5527 } else {
5528 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5529 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5531 checkGLcall("glScissor");
5532 glClear(glMask);
5533 checkGLcall("glClear");
5534 } else {
5535 /* Now process each rect in turn */
5536 for (i = 0; i < Count; i++) {
5537 /* Note gl uses lower left, width/height */
5538 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5539 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5540 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5542 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5543 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5544 curRect.x1, (target->currentDesc.Height - curRect.y2),
5545 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5547 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5548 * The rectangle is not cleared, no error is returned, but further rectanlges are
5549 * still cleared if they are valid
5551 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5552 TRACE("Rectangle with negative dimensions, ignoring\n");
5553 continue;
5556 if(This->render_offscreen) {
5557 glScissor(curRect.x1, curRect.y1,
5558 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5559 } else {
5560 glScissor(curRect.x1, drawable_height - curRect.y2,
5561 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5563 checkGLcall("glScissor");
5565 glClear(glMask);
5566 checkGLcall("glClear");
5570 /* Restore the old values (why..?) */
5571 if (Flags & WINED3DCLEAR_STENCIL) {
5572 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5574 if (Flags & WINED3DCLEAR_TARGET) {
5575 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5576 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5577 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5578 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5579 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5581 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5582 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5584 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5586 if (Flags & WINED3DCLEAR_ZBUFFER) {
5587 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5588 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5589 surface_modify_ds_location(This->stencilBufferTarget, location);
5592 LEAVE_GL();
5594 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5595 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5596 glFlush();
5598 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5601 return WINED3D_OK;
5604 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5605 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5607 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5609 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5610 Count, pRects, Flags, Color, Z, Stencil);
5612 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5613 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5614 /* TODO: What about depth stencil buffers without stencil bits? */
5615 return WINED3DERR_INVALIDCALL;
5618 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5621 /*****
5622 * Drawing functions
5623 *****/
5625 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5626 WINED3DPRIMITIVETYPE primitive_type)
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5630 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5632 This->updateStateBlock->changed.primitive_type = TRUE;
5633 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5636 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5637 WINED3DPRIMITIVETYPE *primitive_type)
5639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5643 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5645 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5648 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5652 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5654 if(!This->stateBlock->vertexDecl) {
5655 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5656 return WINED3DERR_INVALIDCALL;
5659 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5660 if(This->stateBlock->streamIsUP) {
5661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5662 This->stateBlock->streamIsUP = FALSE;
5665 if(This->stateBlock->loadBaseVertexIndex != 0) {
5666 This->stateBlock->loadBaseVertexIndex = 0;
5667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5669 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5670 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5671 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5672 return WINED3D_OK;
5675 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5676 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 UINT idxStride = 2;
5680 IWineD3DIndexBuffer *pIB;
5681 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5682 GLuint vbo;
5684 pIB = This->stateBlock->pIndexData;
5685 if (!pIB) {
5686 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5687 * without an index buffer set. (The first time at least...)
5688 * D3D8 simply dies, but I doubt it can do much harm to return
5689 * D3DERR_INVALIDCALL there as well. */
5690 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5691 return WINED3DERR_INVALIDCALL;
5694 if(!This->stateBlock->vertexDecl) {
5695 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5696 return WINED3DERR_INVALIDCALL;
5699 if(This->stateBlock->streamIsUP) {
5700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5701 This->stateBlock->streamIsUP = FALSE;
5703 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5705 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5706 This, minIndex, NumVertices, startIndex, index_count);
5708 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5709 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5710 idxStride = 2;
5711 } else {
5712 idxStride = 4;
5715 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5716 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5720 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5721 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5727 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 IWineD3DBuffer *vb;
5732 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5733 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5735 if(!This->stateBlock->vertexDecl) {
5736 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5737 return WINED3DERR_INVALIDCALL;
5740 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5741 vb = This->stateBlock->streamSource[0];
5742 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5743 if (vb) IWineD3DBuffer_Release(vb);
5744 This->stateBlock->streamOffset[0] = 0;
5745 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5746 This->stateBlock->streamIsUP = TRUE;
5747 This->stateBlock->loadBaseVertexIndex = 0;
5749 /* TODO: Only mark dirty if drawing from a different UP address */
5750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5752 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5753 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5755 /* MSDN specifies stream zero settings must be set to NULL */
5756 This->stateBlock->streamStride[0] = 0;
5757 This->stateBlock->streamSource[0] = NULL;
5759 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5760 * the new stream sources or use UP drawing again
5762 return WINED3D_OK;
5765 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5766 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5767 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5769 int idxStride;
5770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5771 IWineD3DBuffer *vb;
5772 IWineD3DIndexBuffer *ib;
5774 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5775 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5776 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5778 if(!This->stateBlock->vertexDecl) {
5779 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5780 return WINED3DERR_INVALIDCALL;
5783 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5784 idxStride = 2;
5785 } else {
5786 idxStride = 4;
5789 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5790 vb = This->stateBlock->streamSource[0];
5791 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5792 if (vb) IWineD3DBuffer_Release(vb);
5793 This->stateBlock->streamIsUP = TRUE;
5794 This->stateBlock->streamOffset[0] = 0;
5795 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5797 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5798 This->stateBlock->baseVertexIndex = 0;
5799 This->stateBlock->loadBaseVertexIndex = 0;
5800 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5804 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5805 idxStride, pIndexData, MinVertexIndex);
5807 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5808 This->stateBlock->streamSource[0] = NULL;
5809 This->stateBlock->streamStride[0] = 0;
5810 ib = This->stateBlock->pIndexData;
5811 if(ib) {
5812 IWineD3DIndexBuffer_Release(ib);
5813 This->stateBlock->pIndexData = NULL;
5815 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5816 * SetStreamSource to specify a vertex buffer
5819 return WINED3D_OK;
5822 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5823 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5827 /* Mark the state dirty until we have nicer tracking
5828 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5829 * that value.
5831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5833 This->stateBlock->baseVertexIndex = 0;
5834 This->up_strided = DrawPrimStrideData;
5835 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5836 This->up_strided = NULL;
5837 return WINED3D_OK;
5840 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5841 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5842 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5845 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5847 /* Mark the state dirty until we have nicer tracking
5848 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5849 * that value.
5851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5853 This->stateBlock->streamIsUP = TRUE;
5854 This->stateBlock->baseVertexIndex = 0;
5855 This->up_strided = DrawPrimStrideData;
5856 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5857 This->up_strided = NULL;
5858 return WINED3D_OK;
5861 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5862 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5863 * not callable by the app directly no parameter validation checks are needed here.
5865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5866 WINED3DLOCKED_BOX src;
5867 WINED3DLOCKED_BOX dst;
5868 HRESULT hr;
5869 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5871 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5872 * dirtification to improve loading performance.
5874 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5875 if(FAILED(hr)) return hr;
5876 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5877 if(FAILED(hr)) {
5878 IWineD3DVolume_UnlockBox(pSourceVolume);
5879 return hr;
5882 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5884 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5885 if(FAILED(hr)) {
5886 IWineD3DVolume_UnlockBox(pSourceVolume);
5887 } else {
5888 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5890 return hr;
5893 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5894 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 HRESULT hr = WINED3D_OK;
5897 WINED3DRESOURCETYPE sourceType;
5898 WINED3DRESOURCETYPE destinationType;
5899 int i ,levels;
5901 /* TODO: think about moving the code into IWineD3DBaseTexture */
5903 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5905 /* verify that the source and destination textures aren't NULL */
5906 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5907 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5908 This, pSourceTexture, pDestinationTexture);
5909 hr = WINED3DERR_INVALIDCALL;
5912 if (pSourceTexture == pDestinationTexture) {
5913 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5914 This, pSourceTexture, pDestinationTexture);
5915 hr = WINED3DERR_INVALIDCALL;
5917 /* Verify that the source and destination textures are the same type */
5918 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5919 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5921 if (sourceType != destinationType) {
5922 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5923 This);
5924 hr = WINED3DERR_INVALIDCALL;
5927 /* check that both textures have the identical numbers of levels */
5928 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5929 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5930 hr = WINED3DERR_INVALIDCALL;
5933 if (WINED3D_OK == hr) {
5934 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5936 /* Make sure that the destination texture is loaded */
5937 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5939 /* Update every surface level of the texture */
5940 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5942 switch (sourceType) {
5943 case WINED3DRTYPE_TEXTURE:
5945 IWineD3DSurface *srcSurface;
5946 IWineD3DSurface *destSurface;
5948 for (i = 0 ; i < levels ; ++i) {
5949 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5950 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5951 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5952 IWineD3DSurface_Release(srcSurface);
5953 IWineD3DSurface_Release(destSurface);
5954 if (WINED3D_OK != hr) {
5955 WARN("(%p) : Call to update surface failed\n", This);
5956 return hr;
5960 break;
5961 case WINED3DRTYPE_CUBETEXTURE:
5963 IWineD3DSurface *srcSurface;
5964 IWineD3DSurface *destSurface;
5965 WINED3DCUBEMAP_FACES faceType;
5967 for (i = 0 ; i < levels ; ++i) {
5968 /* Update each cube face */
5969 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5970 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5971 if (WINED3D_OK != hr) {
5972 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5973 } else {
5974 TRACE("Got srcSurface %p\n", srcSurface);
5976 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5977 if (WINED3D_OK != hr) {
5978 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5979 } else {
5980 TRACE("Got desrSurface %p\n", destSurface);
5982 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5983 IWineD3DSurface_Release(srcSurface);
5984 IWineD3DSurface_Release(destSurface);
5985 if (WINED3D_OK != hr) {
5986 WARN("(%p) : Call to update surface failed\n", This);
5987 return hr;
5992 break;
5994 case WINED3DRTYPE_VOLUMETEXTURE:
5996 IWineD3DVolume *srcVolume = NULL;
5997 IWineD3DVolume *destVolume = NULL;
5999 for (i = 0 ; i < levels ; ++i) {
6000 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6001 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6002 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
6003 IWineD3DVolume_Release(srcVolume);
6004 IWineD3DVolume_Release(destVolume);
6005 if (WINED3D_OK != hr) {
6006 WARN("(%p) : Call to update volume failed\n", This);
6007 return hr;
6011 break;
6013 default:
6014 FIXME("(%p) : Unsupported source and destination type\n", This);
6015 hr = WINED3DERR_INVALIDCALL;
6019 return hr;
6022 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6023 IWineD3DSwapChain *swapChain;
6024 HRESULT hr;
6025 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6026 if(hr == WINED3D_OK) {
6027 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6028 IWineD3DSwapChain_Release(swapChain);
6030 return hr;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 IWineD3DBaseTextureImpl *texture;
6036 DWORD i;
6038 TRACE("(%p) : %p\n", This, pNumPasses);
6040 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6041 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
6042 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6043 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6045 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
6046 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6047 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6050 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
6051 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6053 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6054 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6055 return E_FAIL;
6057 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6058 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6059 return E_FAIL;
6061 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6062 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6063 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6064 return E_FAIL;
6068 /* return a sensible default */
6069 *pNumPasses = 1;
6071 TRACE("returning D3D_OK\n");
6072 return WINED3D_OK;
6075 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6077 int i;
6079 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6080 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6081 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6082 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6084 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6089 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6091 int j;
6092 UINT NewSize;
6093 PALETTEENTRY **palettes;
6095 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6097 if (PaletteNumber >= MAX_PALETTES) {
6098 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6099 return WINED3DERR_INVALIDCALL;
6102 if (PaletteNumber >= This->NumberOfPalettes) {
6103 NewSize = This->NumberOfPalettes;
6104 do {
6105 NewSize *= 2;
6106 } while(PaletteNumber >= NewSize);
6107 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6108 if (!palettes) {
6109 ERR("Out of memory!\n");
6110 return E_OUTOFMEMORY;
6112 This->palettes = palettes;
6113 This->NumberOfPalettes = NewSize;
6116 if (!This->palettes[PaletteNumber]) {
6117 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6118 if (!This->palettes[PaletteNumber]) {
6119 ERR("Out of memory!\n");
6120 return E_OUTOFMEMORY;
6124 for (j = 0; j < 256; ++j) {
6125 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6126 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6127 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6128 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6130 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6131 TRACE("(%p) : returning\n", This);
6132 return WINED3D_OK;
6135 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6137 int j;
6138 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6139 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6140 /* What happens in such situation isn't documented; Native seems to silently abort
6141 on such conditions. Return Invalid Call. */
6142 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6143 return WINED3DERR_INVALIDCALL;
6145 for (j = 0; j < 256; ++j) {
6146 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6147 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6148 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6149 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6151 TRACE("(%p) : returning\n", This);
6152 return WINED3D_OK;
6155 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6157 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6158 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6159 (tested with reference rasterizer). Return Invalid Call. */
6160 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6161 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6162 return WINED3DERR_INVALIDCALL;
6164 /*TODO: stateblocks */
6165 if (This->currentPalette != PaletteNumber) {
6166 This->currentPalette = PaletteNumber;
6167 dirtify_p8_texture_samplers(This);
6169 TRACE("(%p) : returning\n", This);
6170 return WINED3D_OK;
6173 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6175 if (PaletteNumber == NULL) {
6176 WARN("(%p) : returning Invalid Call\n", This);
6177 return WINED3DERR_INVALIDCALL;
6179 /*TODO: stateblocks */
6180 *PaletteNumber = This->currentPalette;
6181 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6182 return WINED3D_OK;
6185 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6187 static BOOL warned;
6188 if (!warned)
6190 FIXME("(%p) : stub\n", This);
6191 warned = TRUE;
6194 This->softwareVertexProcessing = bSoftware;
6195 return WINED3D_OK;
6199 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6201 static BOOL warned;
6202 if (!warned)
6204 FIXME("(%p) : stub\n", This);
6205 warned = TRUE;
6207 return This->softwareVertexProcessing;
6211 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6213 IWineD3DSwapChain *swapChain;
6214 HRESULT hr;
6216 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6218 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6219 if(hr == WINED3D_OK){
6220 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6221 IWineD3DSwapChain_Release(swapChain);
6222 }else{
6223 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6225 return hr;
6229 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6231 static BOOL warned;
6232 if(nSegments != 0.0f) {
6233 if (!warned)
6235 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6236 warned = TRUE;
6239 return WINED3D_OK;
6242 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6244 static BOOL warned;
6245 if (!warned)
6247 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6248 warned = TRUE;
6250 return 0.0f;
6253 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6255 /** TODO: remove casts to IWineD3DSurfaceImpl
6256 * NOTE: move code to surface to accomplish this
6257 ****************************************/
6258 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6259 int srcWidth, srcHeight;
6260 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6261 WINED3DFORMAT destFormat, srcFormat;
6262 UINT destSize;
6263 int srcLeft, destLeft, destTop;
6264 WINED3DPOOL srcPool, destPool;
6265 int offset = 0;
6266 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6267 glDescriptor *glDescription = NULL;
6268 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6269 GLenum dummy;
6270 int sampler;
6271 int bpp;
6272 CONVERT_TYPES convert = NO_CONVERSION;
6274 WINED3DSURFACE_DESC winedesc;
6276 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6277 memset(&winedesc, 0, sizeof(winedesc));
6278 winedesc.Width = &srcSurfaceWidth;
6279 winedesc.Height = &srcSurfaceHeight;
6280 winedesc.Pool = &srcPool;
6281 winedesc.Format = &srcFormat;
6283 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6285 winedesc.Width = &destSurfaceWidth;
6286 winedesc.Height = &destSurfaceHeight;
6287 winedesc.Pool = &destPool;
6288 winedesc.Format = &destFormat;
6289 winedesc.Size = &destSize;
6291 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6293 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6294 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6295 return WINED3DERR_INVALIDCALL;
6298 /* This call loads the opengl surface directly, instead of copying the surface to the
6299 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6300 * copy in sysmem and use regular surface loading.
6302 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6303 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6304 if(convert != NO_CONVERSION) {
6305 return IWineD3DSurface_BltFast(pDestinationSurface,
6306 pDestPoint ? pDestPoint->x : 0,
6307 pDestPoint ? pDestPoint->y : 0,
6308 pSourceSurface, pSourceRect, 0);
6311 if (destFormat == WINED3DFMT_UNKNOWN) {
6312 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6313 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6315 /* Get the update surface description */
6316 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6319 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6321 ENTER_GL();
6322 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6323 checkGLcall("glActiveTextureARB");
6324 LEAVE_GL();
6326 /* Make sure the surface is loaded and up to date */
6327 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6328 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6330 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6332 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6333 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6335 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6336 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6337 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6338 srcLeft = pSourceRect ? pSourceRect->left : 0;
6339 destLeft = pDestPoint ? pDestPoint->x : 0;
6340 destTop = pDestPoint ? pDestPoint->y : 0;
6343 /* This function doesn't support compressed textures
6344 the pitch is just bytesPerPixel * width */
6345 if(srcWidth != srcSurfaceWidth || srcLeft ){
6346 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6347 offset += srcLeft * src_format_desc->byte_count;
6348 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6350 /* TODO DXT formats */
6352 if(pSourceRect != NULL && pSourceRect->top != 0){
6353 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6355 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6356 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6357 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6359 /* Sanity check */
6360 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6362 /* need to lock the surface to get the data */
6363 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6366 ENTER_GL();
6368 /* TODO: Cube and volume support */
6369 if(rowoffset != 0){
6370 /* not a whole row so we have to do it a line at a time */
6371 int j;
6373 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6374 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6376 for (j = destTop; j < (srcHeight + destTop); ++j)
6378 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6379 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6380 data += rowoffset;
6383 } else { /* Full width, so just write out the whole texture */
6384 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6386 if (WINED3DFMT_DXT1 == destFormat ||
6387 WINED3DFMT_DXT2 == destFormat ||
6388 WINED3DFMT_DXT3 == destFormat ||
6389 WINED3DFMT_DXT4 == destFormat ||
6390 WINED3DFMT_DXT5 == destFormat) {
6391 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6392 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6393 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6394 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6395 } if (destFormat != srcFormat) {
6396 FIXME("Updating mixed format compressed texture is not curretly support\n");
6397 } else {
6398 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6399 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6401 } else {
6402 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6406 } else {
6407 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6408 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6411 checkGLcall("glTexSubImage2D");
6413 LEAVE_GL();
6415 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6416 sampler = This->rev_tex_unit_map[0];
6417 if (sampler != -1) {
6418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6421 return WINED3D_OK;
6424 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6426 struct WineD3DRectPatch *patch;
6427 GLenum old_primitive_type;
6428 unsigned int i;
6429 struct list *e;
6430 BOOL found;
6431 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6433 if(!(Handle || pRectPatchInfo)) {
6434 /* TODO: Write a test for the return value, thus the FIXME */
6435 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6436 return WINED3DERR_INVALIDCALL;
6439 if(Handle) {
6440 i = PATCHMAP_HASHFUNC(Handle);
6441 found = FALSE;
6442 LIST_FOR_EACH(e, &This->patches[i]) {
6443 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6444 if(patch->Handle == Handle) {
6445 found = TRUE;
6446 break;
6450 if(!found) {
6451 TRACE("Patch does not exist. Creating a new one\n");
6452 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6453 patch->Handle = Handle;
6454 list_add_head(&This->patches[i], &patch->entry);
6455 } else {
6456 TRACE("Found existing patch %p\n", patch);
6458 } else {
6459 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6460 * attributes we have to tesselate, read back, and draw. This needs a patch
6461 * management structure instance. Create one.
6463 * A possible improvement is to check if a vertex shader is used, and if not directly
6464 * draw the patch.
6466 FIXME("Drawing an uncached patch. This is slow\n");
6467 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6470 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6471 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6472 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6473 HRESULT hr;
6474 TRACE("Tesselation density or patch info changed, retesselating\n");
6476 if(pRectPatchInfo) {
6477 patch->RectPatchInfo = *pRectPatchInfo;
6479 patch->numSegs[0] = pNumSegs[0];
6480 patch->numSegs[1] = pNumSegs[1];
6481 patch->numSegs[2] = pNumSegs[2];
6482 patch->numSegs[3] = pNumSegs[3];
6484 hr = tesselate_rectpatch(This, patch);
6485 if(FAILED(hr)) {
6486 WARN("Patch tesselation failed\n");
6488 /* Do not release the handle to store the params of the patch */
6489 if(!Handle) {
6490 HeapFree(GetProcessHeap(), 0, patch);
6492 return hr;
6496 This->currentPatch = patch;
6497 old_primitive_type = This->stateBlock->gl_primitive_type;
6498 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6499 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6500 This->stateBlock->gl_primitive_type = old_primitive_type;
6501 This->currentPatch = NULL;
6503 /* Destroy uncached patches */
6504 if(!Handle) {
6505 HeapFree(GetProcessHeap(), 0, patch->mem);
6506 HeapFree(GetProcessHeap(), 0, patch);
6508 return WINED3D_OK;
6511 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6513 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6514 FIXME("(%p) : Stub\n", This);
6515 return WINED3D_OK;
6518 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6520 int i;
6521 struct WineD3DRectPatch *patch;
6522 struct list *e;
6523 TRACE("(%p) Handle(%d)\n", This, Handle);
6525 i = PATCHMAP_HASHFUNC(Handle);
6526 LIST_FOR_EACH(e, &This->patches[i]) {
6527 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6528 if(patch->Handle == Handle) {
6529 TRACE("Deleting patch %p\n", patch);
6530 list_remove(&patch->entry);
6531 HeapFree(GetProcessHeap(), 0, patch->mem);
6532 HeapFree(GetProcessHeap(), 0, patch);
6533 return WINED3D_OK;
6537 /* TODO: Write a test for the return value */
6538 FIXME("Attempt to destroy nonexistent patch\n");
6539 return WINED3DERR_INVALIDCALL;
6542 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6543 HRESULT hr;
6544 IWineD3DSwapChain *swapchain;
6546 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6547 if (SUCCEEDED(hr)) {
6548 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6549 return swapchain;
6552 return NULL;
6555 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6556 const WINED3DRECT *rect, const float color[4])
6558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6559 IWineD3DSwapChain *swapchain;
6561 swapchain = get_swapchain(surface);
6562 if (swapchain) {
6563 GLenum buffer;
6565 TRACE("Surface %p is onscreen\n", surface);
6567 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6568 ENTER_GL();
6569 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6570 buffer = surface_get_gl_buffer(surface, swapchain);
6571 glDrawBuffer(buffer);
6572 checkGLcall("glDrawBuffer()");
6573 } else {
6574 TRACE("Surface %p is offscreen\n", surface);
6576 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6577 ENTER_GL();
6578 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6579 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6580 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6581 checkGLcall("glFramebufferRenderbufferEXT");
6584 if (rect) {
6585 glEnable(GL_SCISSOR_TEST);
6586 if(!swapchain) {
6587 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6588 } else {
6589 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6590 rect->x2 - rect->x1, rect->y2 - rect->y1);
6592 checkGLcall("glScissor");
6593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6594 } else {
6595 glDisable(GL_SCISSOR_TEST);
6597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6599 glDisable(GL_BLEND);
6600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6602 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6605 glClearColor(color[0], color[1], color[2], color[3]);
6606 glClear(GL_COLOR_BUFFER_BIT);
6607 checkGLcall("glClear");
6609 if (This->activeContext->current_fbo) {
6610 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6611 } else {
6612 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6613 checkGLcall("glBindFramebuffer()");
6616 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6617 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6618 glDrawBuffer(GL_BACK);
6619 checkGLcall("glDrawBuffer()");
6622 LEAVE_GL();
6625 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6626 unsigned int r, g, b, a;
6627 DWORD ret;
6629 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6630 destfmt == WINED3DFMT_R8G8B8)
6631 return color;
6633 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6635 a = (color & 0xff000000) >> 24;
6636 r = (color & 0x00ff0000) >> 16;
6637 g = (color & 0x0000ff00) >> 8;
6638 b = (color & 0x000000ff) >> 0;
6640 switch(destfmt)
6642 case WINED3DFMT_R5G6B5:
6643 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6644 r = (r * 32) / 256;
6645 g = (g * 64) / 256;
6646 b = (b * 32) / 256;
6647 ret = r << 11;
6648 ret |= g << 5;
6649 ret |= b;
6650 TRACE("Returning %08x\n", ret);
6651 return ret;
6653 case WINED3DFMT_X1R5G5B5:
6654 case WINED3DFMT_A1R5G5B5:
6655 a = (a * 2) / 256;
6656 r = (r * 32) / 256;
6657 g = (g * 32) / 256;
6658 b = (b * 32) / 256;
6659 ret = a << 15;
6660 ret |= r << 10;
6661 ret |= g << 5;
6662 ret |= b << 0;
6663 TRACE("Returning %08x\n", ret);
6664 return ret;
6666 case WINED3DFMT_A8_UNORM:
6667 TRACE("Returning %08x\n", a);
6668 return a;
6670 case WINED3DFMT_X4R4G4B4:
6671 case WINED3DFMT_A4R4G4B4:
6672 a = (a * 16) / 256;
6673 r = (r * 16) / 256;
6674 g = (g * 16) / 256;
6675 b = (b * 16) / 256;
6676 ret = a << 12;
6677 ret |= r << 8;
6678 ret |= g << 4;
6679 ret |= b << 0;
6680 TRACE("Returning %08x\n", ret);
6681 return ret;
6683 case WINED3DFMT_R3G3B2:
6684 r = (r * 8) / 256;
6685 g = (g * 8) / 256;
6686 b = (b * 4) / 256;
6687 ret = r << 5;
6688 ret |= g << 2;
6689 ret |= b << 0;
6690 TRACE("Returning %08x\n", ret);
6691 return ret;
6693 case WINED3DFMT_X8B8G8R8:
6694 case WINED3DFMT_R8G8B8A8_UNORM:
6695 ret = a << 24;
6696 ret |= b << 16;
6697 ret |= g << 8;
6698 ret |= r << 0;
6699 TRACE("Returning %08x\n", ret);
6700 return ret;
6702 case WINED3DFMT_A2R10G10B10:
6703 a = (a * 4) / 256;
6704 r = (r * 1024) / 256;
6705 g = (g * 1024) / 256;
6706 b = (b * 1024) / 256;
6707 ret = a << 30;
6708 ret |= r << 20;
6709 ret |= g << 10;
6710 ret |= b << 0;
6711 TRACE("Returning %08x\n", ret);
6712 return ret;
6714 case WINED3DFMT_R10G10B10A2_UNORM:
6715 a = (a * 4) / 256;
6716 r = (r * 1024) / 256;
6717 g = (g * 1024) / 256;
6718 b = (b * 1024) / 256;
6719 ret = a << 30;
6720 ret |= b << 20;
6721 ret |= g << 10;
6722 ret |= r << 0;
6723 TRACE("Returning %08x\n", ret);
6724 return ret;
6726 default:
6727 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6728 return 0;
6732 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6734 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6735 WINEDDBLTFX BltFx;
6736 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6738 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6739 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6740 return WINED3DERR_INVALIDCALL;
6743 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6744 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6745 color_fill_fbo(iface, pSurface, pRect, c);
6746 return WINED3D_OK;
6747 } else {
6748 /* Just forward this to the DirectDraw blitting engine */
6749 memset(&BltFx, 0, sizeof(BltFx));
6750 BltFx.dwSize = sizeof(BltFx);
6751 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6752 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6753 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6757 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6758 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6760 IWineD3DResource *resource;
6761 IWineD3DSurface *surface;
6762 HRESULT hr;
6764 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6765 if (FAILED(hr))
6767 ERR("Failed to get resource, hr %#x\n", hr);
6768 return;
6771 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6773 FIXME("Only supported on surface resources\n");
6774 IWineD3DResource_Release(resource);
6775 return;
6778 surface = (IWineD3DSurface *)resource;
6780 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6782 color_fill_fbo(iface, surface, NULL, color);
6784 else
6786 WINEDDBLTFX BltFx;
6787 WINED3DCOLOR c;
6789 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6791 c = ((DWORD)(color[2] * 255.0));
6792 c |= ((DWORD)(color[1] * 255.0)) << 8;
6793 c |= ((DWORD)(color[0] * 255.0)) << 16;
6794 c |= ((DWORD)(color[3] * 255.0)) << 24;
6796 /* Just forward this to the DirectDraw blitting engine */
6797 memset(&BltFx, 0, sizeof(BltFx));
6798 BltFx.dwSize = sizeof(BltFx);
6799 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6800 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6801 if (FAILED(hr))
6803 ERR("Blt failed, hr %#x\n", hr);
6807 IWineD3DResource_Release(resource);
6810 /* rendertarget and depth stencil functions */
6811 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6814 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6815 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6816 return WINED3DERR_INVALIDCALL;
6819 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6820 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6821 /* Note inc ref on returned surface */
6822 if(*ppRenderTarget != NULL)
6823 IWineD3DSurface_AddRef(*ppRenderTarget);
6824 return WINED3D_OK;
6827 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6829 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6830 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6831 IWineD3DSwapChainImpl *Swapchain;
6832 HRESULT hr;
6834 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6836 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6837 if(hr != WINED3D_OK) {
6838 ERR("Can't get the swapchain\n");
6839 return hr;
6842 /* Make sure to release the swapchain */
6843 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6845 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6846 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6847 return WINED3DERR_INVALIDCALL;
6849 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6850 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6851 return WINED3DERR_INVALIDCALL;
6854 if(Swapchain->frontBuffer != Front) {
6855 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6857 if(Swapchain->frontBuffer)
6859 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6860 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6862 Swapchain->frontBuffer = Front;
6864 if(Swapchain->frontBuffer) {
6865 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6866 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6870 if(Back && !Swapchain->backBuffer) {
6871 /* We need memory for the back buffer array - only one back buffer this way */
6872 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6873 if(!Swapchain->backBuffer) {
6874 ERR("Out of memory\n");
6875 return E_OUTOFMEMORY;
6879 if(Swapchain->backBuffer[0] != Back) {
6880 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6882 /* What to do about the context here in the case of multithreading? Not sure.
6883 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6885 ENTER_GL();
6886 if(!Swapchain->backBuffer[0]) {
6887 /* GL was told to draw to the front buffer at creation,
6888 * undo that
6890 glDrawBuffer(GL_BACK);
6891 checkGLcall("glDrawBuffer(GL_BACK)");
6892 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6893 Swapchain->presentParms.BackBufferCount = 1;
6894 } else if (!Back) {
6895 /* That makes problems - disable for now */
6896 /* glDrawBuffer(GL_FRONT); */
6897 checkGLcall("glDrawBuffer(GL_FRONT)");
6898 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6899 Swapchain->presentParms.BackBufferCount = 0;
6901 LEAVE_GL();
6903 if(Swapchain->backBuffer[0])
6905 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6906 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6908 Swapchain->backBuffer[0] = Back;
6910 if(Swapchain->backBuffer[0]) {
6911 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6912 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6913 } else {
6914 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6915 Swapchain->backBuffer = NULL;
6920 return WINED3D_OK;
6923 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6925 *ppZStencilSurface = This->stencilBufferTarget;
6926 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6928 if(*ppZStencilSurface != NULL) {
6929 /* Note inc ref on returned surface */
6930 IWineD3DSurface_AddRef(*ppZStencilSurface);
6931 return WINED3D_OK;
6932 } else {
6933 return WINED3DERR_NOTFOUND;
6937 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6938 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6941 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6942 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6943 GLenum gl_filter;
6944 POINT offset = {0, 0};
6946 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6947 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6948 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6949 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6951 switch (filter) {
6952 case WINED3DTEXF_LINEAR:
6953 gl_filter = GL_LINEAR;
6954 break;
6956 default:
6957 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6958 case WINED3DTEXF_NONE:
6959 case WINED3DTEXF_POINT:
6960 gl_filter = GL_NEAREST;
6961 break;
6964 /* Attach src surface to src fbo */
6965 src_swapchain = get_swapchain(src_surface);
6966 if (src_swapchain) {
6967 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6969 TRACE("Source surface %p is onscreen\n", src_surface);
6970 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6971 /* Make sure the drawable is up to date. In the offscreen case
6972 * attach_surface_fbo() implicitly takes care of this. */
6973 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6975 if(buffer == GL_FRONT) {
6976 RECT windowsize;
6977 UINT h;
6978 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6979 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6980 h = windowsize.bottom - windowsize.top;
6981 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6982 src_rect->y1 = offset.y + h - src_rect->y1;
6983 src_rect->y2 = offset.y + h - src_rect->y2;
6984 } else {
6985 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6986 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6989 ENTER_GL();
6990 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6991 glReadBuffer(buffer);
6992 checkGLcall("glReadBuffer()");
6993 } else {
6994 TRACE("Source surface %p is offscreen\n", src_surface);
6995 ENTER_GL();
6996 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6997 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6998 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6999 checkGLcall("glReadBuffer()");
7000 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7001 checkGLcall("glFramebufferRenderbufferEXT");
7003 LEAVE_GL();
7005 /* Attach dst surface to dst fbo */
7006 dst_swapchain = get_swapchain(dst_surface);
7007 if (dst_swapchain) {
7008 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
7010 TRACE("Destination surface %p is onscreen\n", dst_surface);
7011 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
7012 /* Make sure the drawable is up to date. In the offscreen case
7013 * attach_surface_fbo() implicitly takes care of this. */
7014 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
7016 if(buffer == GL_FRONT) {
7017 RECT windowsize;
7018 UINT h;
7019 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
7020 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
7021 h = windowsize.bottom - windowsize.top;
7022 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
7023 dst_rect->y1 = offset.y + h - dst_rect->y1;
7024 dst_rect->y2 = offset.y + h - dst_rect->y2;
7025 } else {
7026 /* Screen coords = window coords, surface height = window height */
7027 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
7028 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
7031 ENTER_GL();
7032 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
7033 glDrawBuffer(buffer);
7034 checkGLcall("glDrawBuffer()");
7035 } else {
7036 TRACE("Destination surface %p is offscreen\n", dst_surface);
7038 /* No src or dst swapchain? Make sure some context is active(multithreading) */
7039 if(!src_swapchain) {
7040 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7043 ENTER_GL();
7044 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
7045 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
7046 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
7047 checkGLcall("glDrawBuffer()");
7048 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7049 checkGLcall("glFramebufferRenderbufferEXT");
7051 glDisable(GL_SCISSOR_TEST);
7052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7054 if (flip) {
7055 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7056 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7057 checkGLcall("glBlitFramebuffer()");
7058 } else {
7059 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7060 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7061 checkGLcall("glBlitFramebuffer()");
7064 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7066 if (This->activeContext->current_fbo) {
7067 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7068 } else {
7069 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7070 checkGLcall("glBindFramebuffer()");
7073 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7074 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7075 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7076 glDrawBuffer(GL_BACK);
7077 checkGLcall("glDrawBuffer()");
7079 LEAVE_GL();
7082 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7084 WINED3DVIEWPORT viewport;
7086 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7088 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7089 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7090 This, RenderTargetIndex, GL_LIMITS(buffers));
7091 return WINED3DERR_INVALIDCALL;
7094 /* MSDN says that null disables the render target
7095 but a device must always be associated with a render target
7096 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7098 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7099 FIXME("Trying to set render target 0 to NULL\n");
7100 return WINED3DERR_INVALIDCALL;
7102 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7103 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);
7104 return WINED3DERR_INVALIDCALL;
7107 /* If we are trying to set what we already have, don't bother */
7108 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7109 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7110 return WINED3D_OK;
7112 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7113 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7114 This->render_targets[RenderTargetIndex] = pRenderTarget;
7116 /* Render target 0 is special */
7117 if(RenderTargetIndex == 0) {
7118 /* Finally, reset the viewport as the MSDN states. */
7119 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7120 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7121 viewport.X = 0;
7122 viewport.Y = 0;
7123 viewport.MaxZ = 1.0f;
7124 viewport.MinZ = 0.0f;
7125 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7126 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7127 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7131 return WINED3D_OK;
7134 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7136 HRESULT hr = WINED3D_OK;
7137 IWineD3DSurface *tmp;
7139 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7141 if (pNewZStencil == This->stencilBufferTarget) {
7142 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7143 } else {
7144 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7145 * depending on the renter target implementation being used.
7146 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7147 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7148 * stencil buffer and incur an extra memory overhead
7149 ******************************************************/
7151 if (This->stencilBufferTarget) {
7152 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7153 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7154 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7155 } else {
7156 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7157 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7158 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7162 tmp = This->stencilBufferTarget;
7163 This->stencilBufferTarget = pNewZStencil;
7164 /* should we be calling the parent or the wined3d surface? */
7165 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7166 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7167 hr = WINED3D_OK;
7169 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7170 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7177 return hr;
7180 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7181 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7183 /* TODO: the use of Impl is deprecated. */
7184 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7185 WINED3DLOCKED_RECT lockedRect;
7187 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7189 /* some basic validation checks */
7190 if(This->cursorTexture) {
7191 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7192 ENTER_GL();
7193 glDeleteTextures(1, &This->cursorTexture);
7194 LEAVE_GL();
7195 This->cursorTexture = 0;
7198 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7199 This->haveHardwareCursor = TRUE;
7200 else
7201 This->haveHardwareCursor = FALSE;
7203 if(pCursorBitmap) {
7204 WINED3DLOCKED_RECT rect;
7206 /* MSDN: Cursor must be A8R8G8B8 */
7207 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7209 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7210 return WINED3DERR_INVALIDCALL;
7213 /* MSDN: Cursor must be smaller than the display mode */
7214 if(pSur->currentDesc.Width > This->ddraw_width ||
7215 pSur->currentDesc.Height > This->ddraw_height) {
7216 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);
7217 return WINED3DERR_INVALIDCALL;
7220 if (!This->haveHardwareCursor) {
7221 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7223 /* Do not store the surface's pointer because the application may
7224 * release it after setting the cursor image. Windows doesn't
7225 * addref the set surface, so we can't do this either without
7226 * creating circular refcount dependencies. Copy out the gl texture
7227 * instead.
7229 This->cursorWidth = pSur->currentDesc.Width;
7230 This->cursorHeight = pSur->currentDesc.Height;
7231 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7233 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7234 char *mem, *bits = rect.pBits;
7235 GLint intfmt = glDesc->glInternal;
7236 GLint format = glDesc->glFormat;
7237 GLint type = glDesc->glType;
7238 INT height = This->cursorHeight;
7239 INT width = This->cursorWidth;
7240 INT bpp = glDesc->byte_count;
7241 INT i, sampler;
7243 /* Reformat the texture memory (pitch and width can be
7244 * different) */
7245 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7246 for(i = 0; i < height; i++)
7247 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7248 IWineD3DSurface_UnlockRect(pCursorBitmap);
7249 ENTER_GL();
7251 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7252 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7253 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7256 /* Make sure that a proper texture unit is selected */
7257 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7258 checkGLcall("glActiveTextureARB");
7259 sampler = This->rev_tex_unit_map[0];
7260 if (sampler != -1) {
7261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7263 /* Create a new cursor texture */
7264 glGenTextures(1, &This->cursorTexture);
7265 checkGLcall("glGenTextures");
7266 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7267 checkGLcall("glBindTexture");
7268 /* Copy the bitmap memory into the cursor texture */
7269 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7270 HeapFree(GetProcessHeap(), 0, mem);
7271 checkGLcall("glTexImage2D");
7273 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7274 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7275 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7278 LEAVE_GL();
7280 else
7282 FIXME("A cursor texture was not returned.\n");
7283 This->cursorTexture = 0;
7286 else
7288 /* Draw a hardware cursor */
7289 ICONINFO cursorInfo;
7290 HCURSOR cursor;
7291 /* Create and clear maskBits because it is not needed for
7292 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7293 * chunks. */
7294 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7295 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7296 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7297 WINED3DLOCK_NO_DIRTY_UPDATE |
7298 WINED3DLOCK_READONLY
7300 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7301 pSur->currentDesc.Height);
7303 cursorInfo.fIcon = FALSE;
7304 cursorInfo.xHotspot = XHotSpot;
7305 cursorInfo.yHotspot = YHotSpot;
7306 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7307 pSur->currentDesc.Height, 1,
7308 1, &maskBits);
7309 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7310 pSur->currentDesc.Height, 1,
7311 32, lockedRect.pBits);
7312 IWineD3DSurface_UnlockRect(pCursorBitmap);
7313 /* Create our cursor and clean up. */
7314 cursor = CreateIconIndirect(&cursorInfo);
7315 SetCursor(cursor);
7316 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7317 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7318 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7319 This->hardwareCursor = cursor;
7320 HeapFree(GetProcessHeap(), 0, maskBits);
7324 This->xHotSpot = XHotSpot;
7325 This->yHotSpot = YHotSpot;
7326 return WINED3D_OK;
7329 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7331 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7333 This->xScreenSpace = XScreenSpace;
7334 This->yScreenSpace = YScreenSpace;
7336 return;
7340 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7342 BOOL oldVisible = This->bCursorVisible;
7343 POINT pt;
7345 TRACE("(%p) : visible(%d)\n", This, bShow);
7348 * When ShowCursor is first called it should make the cursor appear at the OS's last
7349 * known cursor position. Because of this, some applications just repetitively call
7350 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7352 GetCursorPos(&pt);
7353 This->xScreenSpace = pt.x;
7354 This->yScreenSpace = pt.y;
7356 if (This->haveHardwareCursor) {
7357 This->bCursorVisible = bShow;
7358 if (bShow)
7359 SetCursor(This->hardwareCursor);
7360 else
7361 SetCursor(NULL);
7363 else
7365 if (This->cursorTexture)
7366 This->bCursorVisible = bShow;
7369 return oldVisible;
7372 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7374 IWineD3DResourceImpl *resource;
7375 TRACE("(%p) : state (%u)\n", This, This->state);
7377 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7378 switch (This->state) {
7379 case WINED3D_OK:
7380 return WINED3D_OK;
7381 case WINED3DERR_DEVICELOST:
7383 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7384 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7385 return WINED3DERR_DEVICENOTRESET;
7387 return WINED3DERR_DEVICELOST;
7389 case WINED3DERR_DRIVERINTERNALERROR:
7390 return WINED3DERR_DRIVERINTERNALERROR;
7393 /* Unknown state */
7394 return WINED3DERR_DRIVERINTERNALERROR;
7398 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7400 /** FIXME: Resource tracking needs to be done,
7401 * The closes we can do to this is set the priorities of all managed textures low
7402 * and then reset them.
7403 ***********************************************************/
7404 FIXME("(%p) : stub\n", This);
7405 return WINED3D_OK;
7408 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7410 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7412 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7413 if(surface->Flags & SFLAG_DIBSECTION) {
7414 /* Release the DC */
7415 SelectObject(surface->hDC, surface->dib.holdbitmap);
7416 DeleteDC(surface->hDC);
7417 /* Release the DIB section */
7418 DeleteObject(surface->dib.DIBsection);
7419 surface->dib.bitmap_data = NULL;
7420 surface->resource.allocatedMemory = NULL;
7421 surface->Flags &= ~SFLAG_DIBSECTION;
7423 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7424 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7425 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7426 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7427 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7428 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7429 } else {
7430 surface->pow2Width = surface->pow2Height = 1;
7431 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7432 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7434 surface->glRect.left = 0;
7435 surface->glRect.top = 0;
7436 surface->glRect.right = surface->pow2Width;
7437 surface->glRect.bottom = surface->pow2Height;
7439 if(surface->glDescription.textureName) {
7440 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7441 ENTER_GL();
7442 glDeleteTextures(1, &surface->glDescription.textureName);
7443 LEAVE_GL();
7444 surface->glDescription.textureName = 0;
7445 surface->Flags &= ~SFLAG_CLIENT;
7447 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7448 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7449 surface->Flags |= SFLAG_NONPOW2;
7450 } else {
7451 surface->Flags &= ~SFLAG_NONPOW2;
7453 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7454 surface->resource.allocatedMemory = NULL;
7455 surface->resource.heapMemory = NULL;
7456 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7457 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7458 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7459 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7460 } else {
7461 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7465 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7466 TRACE("Unloading resource %p\n", resource);
7467 IWineD3DResource_UnLoad(resource);
7468 IWineD3DResource_Release(resource);
7469 return S_OK;
7472 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7474 UINT i, count;
7475 WINED3DDISPLAYMODE m;
7476 HRESULT hr;
7478 /* All Windowed modes are supported, as is leaving the current mode */
7479 if(pp->Windowed) return TRUE;
7480 if(!pp->BackBufferWidth) return TRUE;
7481 if(!pp->BackBufferHeight) return TRUE;
7483 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7484 for(i = 0; i < count; i++) {
7485 memset(&m, 0, sizeof(m));
7486 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7487 if(FAILED(hr)) {
7488 ERR("EnumAdapterModes failed\n");
7490 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7491 /* Mode found, it is supported */
7492 return TRUE;
7495 /* Mode not found -> not supported */
7496 return FALSE;
7499 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7501 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7502 UINT i;
7503 IWineD3DBaseShaderImpl *shader;
7505 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7506 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7507 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7510 ENTER_GL();
7511 if(This->depth_blt_texture) {
7512 glDeleteTextures(1, &This->depth_blt_texture);
7513 This->depth_blt_texture = 0;
7515 if (This->depth_blt_rb) {
7516 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7517 This->depth_blt_rb = 0;
7518 This->depth_blt_rb_w = 0;
7519 This->depth_blt_rb_h = 0;
7521 LEAVE_GL();
7523 This->blitter->free_private(iface);
7524 This->frag_pipe->free_private(iface);
7525 This->shader_backend->shader_free_private(iface);
7527 ENTER_GL();
7528 for (i = 0; i < GL_LIMITS(textures); i++) {
7529 /* Textures are recreated below */
7530 glDeleteTextures(1, &This->dummyTextureName[i]);
7531 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7532 This->dummyTextureName[i] = 0;
7534 LEAVE_GL();
7536 while(This->numContexts) {
7537 DestroyContext(This, This->contexts[0]);
7539 This->activeContext = NULL;
7540 HeapFree(GetProcessHeap(), 0, swapchain->context);
7541 swapchain->context = NULL;
7542 swapchain->num_contexts = 0;
7545 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7547 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7548 HRESULT hr;
7549 IWineD3DSurfaceImpl *target;
7551 /* Recreate the primary swapchain's context */
7552 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7553 if(swapchain->backBuffer) {
7554 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7555 } else {
7556 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7558 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7559 &swapchain->presentParms);
7560 swapchain->num_contexts = 1;
7561 This->activeContext = swapchain->context[0];
7563 create_dummy_textures(This);
7565 hr = This->shader_backend->shader_alloc_private(iface);
7566 if(FAILED(hr)) {
7567 ERR("Failed to recreate shader private data\n");
7568 goto err_out;
7570 hr = This->frag_pipe->alloc_private(iface);
7571 if(FAILED(hr)) {
7572 TRACE("Fragment pipeline private data couldn't be allocated\n");
7573 goto err_out;
7575 hr = This->blitter->alloc_private(iface);
7576 if(FAILED(hr)) {
7577 TRACE("Blitter private data couldn't be allocated\n");
7578 goto err_out;
7581 return WINED3D_OK;
7583 err_out:
7584 This->blitter->free_private(iface);
7585 This->frag_pipe->free_private(iface);
7586 This->shader_backend->shader_free_private(iface);
7587 return hr;
7590 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7592 IWineD3DSwapChainImpl *swapchain;
7593 HRESULT hr;
7594 BOOL DisplayModeChanged = FALSE;
7595 WINED3DDISPLAYMODE mode;
7596 TRACE("(%p)\n", This);
7598 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7599 if(FAILED(hr)) {
7600 ERR("Failed to get the first implicit swapchain\n");
7601 return hr;
7604 if(!is_display_mode_supported(This, pPresentationParameters)) {
7605 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7606 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7607 pPresentationParameters->BackBufferHeight);
7608 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7609 return WINED3DERR_INVALIDCALL;
7612 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7613 * on an existing gl context, so there's no real need for recreation.
7615 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7617 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7619 TRACE("New params:\n");
7620 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7621 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7622 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7623 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7624 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7625 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7626 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7627 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7628 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7629 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7630 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7631 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7632 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7634 /* No special treatment of these parameters. Just store them */
7635 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7636 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7637 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7638 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7640 /* What to do about these? */
7641 if(pPresentationParameters->BackBufferCount != 0 &&
7642 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7643 ERR("Cannot change the back buffer count yet\n");
7645 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7646 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7647 ERR("Cannot change the back buffer format yet\n");
7649 if(pPresentationParameters->hDeviceWindow != NULL &&
7650 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7651 ERR("Cannot change the device window yet\n");
7653 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7654 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7655 return WINED3DERR_INVALIDCALL;
7658 /* Reset the depth stencil */
7659 if (pPresentationParameters->EnableAutoDepthStencil)
7660 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7661 else
7662 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7664 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7666 if(pPresentationParameters->Windowed) {
7667 mode.Width = swapchain->orig_width;
7668 mode.Height = swapchain->orig_height;
7669 mode.RefreshRate = 0;
7670 mode.Format = swapchain->presentParms.BackBufferFormat;
7671 } else {
7672 mode.Width = pPresentationParameters->BackBufferWidth;
7673 mode.Height = pPresentationParameters->BackBufferHeight;
7674 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7675 mode.Format = swapchain->presentParms.BackBufferFormat;
7678 /* Should Width == 800 && Height == 0 set 800x600? */
7679 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7680 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7681 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7683 UINT i;
7685 if(!pPresentationParameters->Windowed) {
7686 DisplayModeChanged = TRUE;
7688 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7689 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7691 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7692 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7693 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7695 if(This->auto_depth_stencil_buffer) {
7696 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7700 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7701 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7702 DisplayModeChanged) {
7704 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7706 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7707 if(swapchain->presentParms.Windowed) {
7708 /* switch from windowed to fs */
7709 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7710 pPresentationParameters->BackBufferWidth,
7711 pPresentationParameters->BackBufferHeight);
7712 } else {
7713 /* Fullscreen -> fullscreen mode change */
7714 MoveWindow(swapchain->win_handle, 0, 0,
7715 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7716 TRUE);
7718 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7719 /* Fullscreen -> windowed switch */
7720 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7722 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7723 } else if(!pPresentationParameters->Windowed) {
7724 DWORD style = This->style, exStyle = This->exStyle;
7725 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7726 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7727 * Reset to clear up their mess. Guild Wars also loses the device during that.
7729 This->style = 0;
7730 This->exStyle = 0;
7731 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7732 pPresentationParameters->BackBufferWidth,
7733 pPresentationParameters->BackBufferHeight);
7734 This->style = style;
7735 This->exStyle = exStyle;
7738 TRACE("Resetting stateblock\n");
7739 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7740 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7742 /* Note: No parent needed for initial internal stateblock */
7743 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7744 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7745 else TRACE("Created stateblock %p\n", This->stateBlock);
7746 This->updateStateBlock = This->stateBlock;
7747 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7749 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7750 if(FAILED(hr)) {
7751 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7754 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7755 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7757 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7758 * first use
7760 return hr;
7763 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7765 /** FIXME: always true at the moment **/
7766 if(!bEnableDialogs) {
7767 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7769 return WINED3D_OK;
7773 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7775 TRACE("(%p) : pParameters %p\n", This, pParameters);
7777 *pParameters = This->createParms;
7778 return WINED3D_OK;
7781 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7782 IWineD3DSwapChain *swapchain;
7784 TRACE("Relaying to swapchain\n");
7786 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7787 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7788 IWineD3DSwapChain_Release(swapchain);
7790 return;
7793 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7794 IWineD3DSwapChain *swapchain;
7796 TRACE("Relaying to swapchain\n");
7798 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7799 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7800 IWineD3DSwapChain_Release(swapchain);
7802 return;
7806 /** ********************************************************
7807 * Notification functions
7808 ** ********************************************************/
7809 /** This function must be called in the release of a resource when ref == 0,
7810 * the contents of resource must still be correct,
7811 * any handles to other resource held by the caller must be closed
7812 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7813 *****************************************************/
7814 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7817 TRACE("(%p) : Adding Resource %p\n", This, resource);
7818 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7821 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7824 TRACE("(%p) : Removing resource %p\n", This, resource);
7826 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7830 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7832 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7833 int counter;
7835 TRACE("(%p) : resource %p\n", This, resource);
7837 context_resource_released(iface, resource, type);
7839 switch (type) {
7840 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7841 case WINED3DRTYPE_SURFACE: {
7842 unsigned int i;
7844 /* Cleanup any FBO attachments if d3d is enabled */
7845 if(This->d3d_initialized) {
7846 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7847 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7849 TRACE("Last active render target destroyed\n");
7850 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7851 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7852 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7853 * and the lastActiveRenderTarget member shouldn't matter
7855 if(swapchain) {
7856 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7857 TRACE("Activating primary back buffer\n");
7858 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7859 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7860 /* Single buffering environment */
7861 TRACE("Activating primary front buffer\n");
7862 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7863 } else {
7864 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7865 /* Implicit render target destroyed, that means the device is being destroyed
7866 * whatever we set here, it shouldn't matter
7868 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7870 } else {
7871 /* May happen during ddraw uninitialization */
7872 TRACE("Render target set, but swapchain does not exist!\n");
7873 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7877 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7878 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7879 This->render_targets[i] = NULL;
7882 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7883 This->stencilBufferTarget = NULL;
7887 break;
7889 case WINED3DRTYPE_TEXTURE:
7890 case WINED3DRTYPE_CUBETEXTURE:
7891 case WINED3DRTYPE_VOLUMETEXTURE:
7892 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7893 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7894 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7895 This->stateBlock->textures[counter] = NULL;
7897 if (This->updateStateBlock != This->stateBlock ){
7898 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7899 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7900 This->updateStateBlock->textures[counter] = NULL;
7904 break;
7905 case WINED3DRTYPE_VOLUME:
7906 /* TODO: nothing really? */
7907 break;
7908 case WINED3DRTYPE_BUFFER:
7910 int streamNumber;
7911 TRACE("Cleaning up stream pointers\n");
7913 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7914 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7915 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7917 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7918 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7919 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7920 This->updateStateBlock->streamSource[streamNumber] = 0;
7921 /* Set changed flag? */
7924 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) */
7925 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7926 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7927 This->stateBlock->streamSource[streamNumber] = 0;
7932 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7933 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7934 This->updateStateBlock->pIndexData = NULL;
7937 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7938 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7939 This->stateBlock->pIndexData = NULL;
7943 break;
7945 default:
7946 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7947 break;
7951 /* Remove the resource from the resourceStore */
7952 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7954 TRACE("Resource released\n");
7958 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7960 IWineD3DResourceImpl *resource, *cursor;
7961 HRESULT ret;
7962 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7964 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7965 TRACE("enumerating resource %p\n", resource);
7966 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7967 ret = pCallback((IWineD3DResource *) resource, pData);
7968 if(ret == S_FALSE) {
7969 TRACE("Canceling enumeration\n");
7970 break;
7973 return WINED3D_OK;
7976 /**********************************************************
7977 * IWineD3DDevice VTbl follows
7978 **********************************************************/
7980 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7982 /*** IUnknown methods ***/
7983 IWineD3DDeviceImpl_QueryInterface,
7984 IWineD3DDeviceImpl_AddRef,
7985 IWineD3DDeviceImpl_Release,
7986 /*** IWineD3DDevice methods ***/
7987 IWineD3DDeviceImpl_GetParent,
7988 /*** Creation methods**/
7989 IWineD3DDeviceImpl_CreateBuffer,
7990 IWineD3DDeviceImpl_CreateVertexBuffer,
7991 IWineD3DDeviceImpl_CreateIndexBuffer,
7992 IWineD3DDeviceImpl_CreateStateBlock,
7993 IWineD3DDeviceImpl_CreateSurface,
7994 IWineD3DDeviceImpl_CreateRendertargetView,
7995 IWineD3DDeviceImpl_CreateTexture,
7996 IWineD3DDeviceImpl_CreateVolumeTexture,
7997 IWineD3DDeviceImpl_CreateVolume,
7998 IWineD3DDeviceImpl_CreateCubeTexture,
7999 IWineD3DDeviceImpl_CreateQuery,
8000 IWineD3DDeviceImpl_CreateSwapChain,
8001 IWineD3DDeviceImpl_CreateVertexDeclaration,
8002 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
8003 IWineD3DDeviceImpl_CreateVertexShader,
8004 IWineD3DDeviceImpl_CreatePixelShader,
8005 IWineD3DDeviceImpl_CreatePalette,
8006 /*** Odd functions **/
8007 IWineD3DDeviceImpl_Init3D,
8008 IWineD3DDeviceImpl_InitGDI,
8009 IWineD3DDeviceImpl_Uninit3D,
8010 IWineD3DDeviceImpl_UninitGDI,
8011 IWineD3DDeviceImpl_SetMultithreaded,
8012 IWineD3DDeviceImpl_EvictManagedResources,
8013 IWineD3DDeviceImpl_GetAvailableTextureMem,
8014 IWineD3DDeviceImpl_GetBackBuffer,
8015 IWineD3DDeviceImpl_GetCreationParameters,
8016 IWineD3DDeviceImpl_GetDeviceCaps,
8017 IWineD3DDeviceImpl_GetDirect3D,
8018 IWineD3DDeviceImpl_GetDisplayMode,
8019 IWineD3DDeviceImpl_SetDisplayMode,
8020 IWineD3DDeviceImpl_GetNumberOfSwapChains,
8021 IWineD3DDeviceImpl_GetRasterStatus,
8022 IWineD3DDeviceImpl_GetSwapChain,
8023 IWineD3DDeviceImpl_Reset,
8024 IWineD3DDeviceImpl_SetDialogBoxMode,
8025 IWineD3DDeviceImpl_SetCursorProperties,
8026 IWineD3DDeviceImpl_SetCursorPosition,
8027 IWineD3DDeviceImpl_ShowCursor,
8028 IWineD3DDeviceImpl_TestCooperativeLevel,
8029 /*** Getters and setters **/
8030 IWineD3DDeviceImpl_SetClipPlane,
8031 IWineD3DDeviceImpl_GetClipPlane,
8032 IWineD3DDeviceImpl_SetClipStatus,
8033 IWineD3DDeviceImpl_GetClipStatus,
8034 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8035 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8036 IWineD3DDeviceImpl_SetDepthStencilSurface,
8037 IWineD3DDeviceImpl_GetDepthStencilSurface,
8038 IWineD3DDeviceImpl_SetGammaRamp,
8039 IWineD3DDeviceImpl_GetGammaRamp,
8040 IWineD3DDeviceImpl_SetIndices,
8041 IWineD3DDeviceImpl_GetIndices,
8042 IWineD3DDeviceImpl_SetBaseVertexIndex,
8043 IWineD3DDeviceImpl_GetBaseVertexIndex,
8044 IWineD3DDeviceImpl_SetLight,
8045 IWineD3DDeviceImpl_GetLight,
8046 IWineD3DDeviceImpl_SetLightEnable,
8047 IWineD3DDeviceImpl_GetLightEnable,
8048 IWineD3DDeviceImpl_SetMaterial,
8049 IWineD3DDeviceImpl_GetMaterial,
8050 IWineD3DDeviceImpl_SetNPatchMode,
8051 IWineD3DDeviceImpl_GetNPatchMode,
8052 IWineD3DDeviceImpl_SetPaletteEntries,
8053 IWineD3DDeviceImpl_GetPaletteEntries,
8054 IWineD3DDeviceImpl_SetPixelShader,
8055 IWineD3DDeviceImpl_GetPixelShader,
8056 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8057 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8058 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8059 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8060 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8061 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8062 IWineD3DDeviceImpl_SetRenderState,
8063 IWineD3DDeviceImpl_GetRenderState,
8064 IWineD3DDeviceImpl_SetRenderTarget,
8065 IWineD3DDeviceImpl_GetRenderTarget,
8066 IWineD3DDeviceImpl_SetFrontBackBuffers,
8067 IWineD3DDeviceImpl_SetSamplerState,
8068 IWineD3DDeviceImpl_GetSamplerState,
8069 IWineD3DDeviceImpl_SetScissorRect,
8070 IWineD3DDeviceImpl_GetScissorRect,
8071 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8072 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8073 IWineD3DDeviceImpl_SetStreamSource,
8074 IWineD3DDeviceImpl_GetStreamSource,
8075 IWineD3DDeviceImpl_SetStreamSourceFreq,
8076 IWineD3DDeviceImpl_GetStreamSourceFreq,
8077 IWineD3DDeviceImpl_SetTexture,
8078 IWineD3DDeviceImpl_GetTexture,
8079 IWineD3DDeviceImpl_SetTextureStageState,
8080 IWineD3DDeviceImpl_GetTextureStageState,
8081 IWineD3DDeviceImpl_SetTransform,
8082 IWineD3DDeviceImpl_GetTransform,
8083 IWineD3DDeviceImpl_SetVertexDeclaration,
8084 IWineD3DDeviceImpl_GetVertexDeclaration,
8085 IWineD3DDeviceImpl_SetVertexShader,
8086 IWineD3DDeviceImpl_GetVertexShader,
8087 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8088 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8089 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8090 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8091 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8092 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8093 IWineD3DDeviceImpl_SetViewport,
8094 IWineD3DDeviceImpl_GetViewport,
8095 IWineD3DDeviceImpl_MultiplyTransform,
8096 IWineD3DDeviceImpl_ValidateDevice,
8097 IWineD3DDeviceImpl_ProcessVertices,
8098 /*** State block ***/
8099 IWineD3DDeviceImpl_BeginStateBlock,
8100 IWineD3DDeviceImpl_EndStateBlock,
8101 /*** Scene management ***/
8102 IWineD3DDeviceImpl_BeginScene,
8103 IWineD3DDeviceImpl_EndScene,
8104 IWineD3DDeviceImpl_Present,
8105 IWineD3DDeviceImpl_Clear,
8106 IWineD3DDeviceImpl_ClearRendertargetView,
8107 /*** Drawing ***/
8108 IWineD3DDeviceImpl_SetPrimitiveType,
8109 IWineD3DDeviceImpl_GetPrimitiveType,
8110 IWineD3DDeviceImpl_DrawPrimitive,
8111 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8112 IWineD3DDeviceImpl_DrawPrimitiveUP,
8113 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8114 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8115 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8116 IWineD3DDeviceImpl_DrawRectPatch,
8117 IWineD3DDeviceImpl_DrawTriPatch,
8118 IWineD3DDeviceImpl_DeletePatch,
8119 IWineD3DDeviceImpl_ColorFill,
8120 IWineD3DDeviceImpl_UpdateTexture,
8121 IWineD3DDeviceImpl_UpdateSurface,
8122 IWineD3DDeviceImpl_GetFrontBufferData,
8123 /*** object tracking ***/
8124 IWineD3DDeviceImpl_ResourceReleased,
8125 IWineD3DDeviceImpl_EnumResources
8128 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8129 WINED3DRS_ALPHABLENDENABLE ,
8130 WINED3DRS_ALPHAFUNC ,
8131 WINED3DRS_ALPHAREF ,
8132 WINED3DRS_ALPHATESTENABLE ,
8133 WINED3DRS_BLENDOP ,
8134 WINED3DRS_COLORWRITEENABLE ,
8135 WINED3DRS_DESTBLEND ,
8136 WINED3DRS_DITHERENABLE ,
8137 WINED3DRS_FILLMODE ,
8138 WINED3DRS_FOGDENSITY ,
8139 WINED3DRS_FOGEND ,
8140 WINED3DRS_FOGSTART ,
8141 WINED3DRS_LASTPIXEL ,
8142 WINED3DRS_SHADEMODE ,
8143 WINED3DRS_SRCBLEND ,
8144 WINED3DRS_STENCILENABLE ,
8145 WINED3DRS_STENCILFAIL ,
8146 WINED3DRS_STENCILFUNC ,
8147 WINED3DRS_STENCILMASK ,
8148 WINED3DRS_STENCILPASS ,
8149 WINED3DRS_STENCILREF ,
8150 WINED3DRS_STENCILWRITEMASK ,
8151 WINED3DRS_STENCILZFAIL ,
8152 WINED3DRS_TEXTUREFACTOR ,
8153 WINED3DRS_WRAP0 ,
8154 WINED3DRS_WRAP1 ,
8155 WINED3DRS_WRAP2 ,
8156 WINED3DRS_WRAP3 ,
8157 WINED3DRS_WRAP4 ,
8158 WINED3DRS_WRAP5 ,
8159 WINED3DRS_WRAP6 ,
8160 WINED3DRS_WRAP7 ,
8161 WINED3DRS_ZENABLE ,
8162 WINED3DRS_ZFUNC ,
8163 WINED3DRS_ZWRITEENABLE
8166 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8167 WINED3DTSS_ALPHAARG0 ,
8168 WINED3DTSS_ALPHAARG1 ,
8169 WINED3DTSS_ALPHAARG2 ,
8170 WINED3DTSS_ALPHAOP ,
8171 WINED3DTSS_BUMPENVLOFFSET ,
8172 WINED3DTSS_BUMPENVLSCALE ,
8173 WINED3DTSS_BUMPENVMAT00 ,
8174 WINED3DTSS_BUMPENVMAT01 ,
8175 WINED3DTSS_BUMPENVMAT10 ,
8176 WINED3DTSS_BUMPENVMAT11 ,
8177 WINED3DTSS_COLORARG0 ,
8178 WINED3DTSS_COLORARG1 ,
8179 WINED3DTSS_COLORARG2 ,
8180 WINED3DTSS_COLOROP ,
8181 WINED3DTSS_RESULTARG ,
8182 WINED3DTSS_TEXCOORDINDEX ,
8183 WINED3DTSS_TEXTURETRANSFORMFLAGS
8186 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8187 WINED3DSAMP_ADDRESSU ,
8188 WINED3DSAMP_ADDRESSV ,
8189 WINED3DSAMP_ADDRESSW ,
8190 WINED3DSAMP_BORDERCOLOR ,
8191 WINED3DSAMP_MAGFILTER ,
8192 WINED3DSAMP_MINFILTER ,
8193 WINED3DSAMP_MIPFILTER ,
8194 WINED3DSAMP_MIPMAPLODBIAS ,
8195 WINED3DSAMP_MAXMIPLEVEL ,
8196 WINED3DSAMP_MAXANISOTROPY ,
8197 WINED3DSAMP_SRGBTEXTURE ,
8198 WINED3DSAMP_ELEMENTINDEX
8201 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8202 WINED3DRS_AMBIENT ,
8203 WINED3DRS_AMBIENTMATERIALSOURCE ,
8204 WINED3DRS_CLIPPING ,
8205 WINED3DRS_CLIPPLANEENABLE ,
8206 WINED3DRS_COLORVERTEX ,
8207 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8208 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8209 WINED3DRS_FOGDENSITY ,
8210 WINED3DRS_FOGEND ,
8211 WINED3DRS_FOGSTART ,
8212 WINED3DRS_FOGTABLEMODE ,
8213 WINED3DRS_FOGVERTEXMODE ,
8214 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8215 WINED3DRS_LIGHTING ,
8216 WINED3DRS_LOCALVIEWER ,
8217 WINED3DRS_MULTISAMPLEANTIALIAS ,
8218 WINED3DRS_MULTISAMPLEMASK ,
8219 WINED3DRS_NORMALIZENORMALS ,
8220 WINED3DRS_PATCHEDGESTYLE ,
8221 WINED3DRS_POINTSCALE_A ,
8222 WINED3DRS_POINTSCALE_B ,
8223 WINED3DRS_POINTSCALE_C ,
8224 WINED3DRS_POINTSCALEENABLE ,
8225 WINED3DRS_POINTSIZE ,
8226 WINED3DRS_POINTSIZE_MAX ,
8227 WINED3DRS_POINTSIZE_MIN ,
8228 WINED3DRS_POINTSPRITEENABLE ,
8229 WINED3DRS_RANGEFOGENABLE ,
8230 WINED3DRS_SPECULARMATERIALSOURCE ,
8231 WINED3DRS_TWEENFACTOR ,
8232 WINED3DRS_VERTEXBLEND ,
8233 WINED3DRS_CULLMODE ,
8234 WINED3DRS_FOGCOLOR
8237 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8238 WINED3DTSS_TEXCOORDINDEX ,
8239 WINED3DTSS_TEXTURETRANSFORMFLAGS
8242 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8243 WINED3DSAMP_DMAPOFFSET
8246 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8247 DWORD rep = This->StateTable[state].representative;
8248 DWORD idx;
8249 BYTE shift;
8250 UINT i;
8251 WineD3DContext *context;
8253 if(!rep) return;
8254 for(i = 0; i < This->numContexts; i++) {
8255 context = This->contexts[i];
8256 if(isStateDirty(context, rep)) continue;
8258 context->dirtyArray[context->numDirtyEntries++] = rep;
8259 idx = rep >> 5;
8260 shift = rep & 0x1f;
8261 context->isStateDirty[idx] |= (1 << shift);
8265 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8266 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8267 /* The drawable size of a pbuffer render target is the current pbuffer size
8269 *width = dev->pbufferWidth;
8270 *height = dev->pbufferHeight;
8273 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8274 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8276 *width = This->pow2Width;
8277 *height = This->pow2Height;
8280 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8281 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8282 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8283 * current context's drawable, which is the size of the back buffer of the swapchain
8284 * the active context belongs to. The back buffer of the swapchain is stored as the
8285 * surface the context belongs to.
8287 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8288 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;