VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/device.c@ 20817

Last change on this file since 20817 was 20612, checked in by vboxsync, 16 years ago

crOpenGL: update wine to 1.1.23

  • Property svn:eol-style set to native
File size: 309.9 KB
Line 
1/*
2 * IWineD3DDevice implementation
3 *
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
12 *
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.
17 *
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.
22 *
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
26 */
27
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36
37#include "config.h"
38#include <stdio.h>
39#ifdef HAVE_FLOAT_H
40# include <float.h>
41#endif
42#include "wined3d_private.h"
43
44WINE_DEFAULT_DEBUG_CHANNEL(d3d);
45#define GLINFO_LOCATION This->adapter->gl_info
46
47/* Define the default light parameters as specified by MSDN */
48const WINED3DLIGHT WINED3D_default_light = {
49
50 WINED3DLIGHT_DIRECTIONAL, /* Type */
51 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
52 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
53 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
54 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
55 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
56 0.0, /* Range */
57 0.0, /* Falloff */
58 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
59 0.0, /* Theta */
60 0.0 /* Phi */
61};
62
63/**********************************************************
64 * Global variable / Constants follow
65 **********************************************************/
66const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
67
68/* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
69 * actually have the same values in GL and D3D. */
70static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
71{
72 switch(primitive_type)
73 {
74 case WINED3DPT_POINTLIST:
75 return GL_POINTS;
76
77 case WINED3DPT_LINELIST:
78 return GL_LINES;
79
80 case WINED3DPT_LINESTRIP:
81 return GL_LINE_STRIP;
82
83 case WINED3DPT_TRIANGLELIST:
84 return GL_TRIANGLES;
85
86 case WINED3DPT_TRIANGLESTRIP:
87 return GL_TRIANGLE_STRIP;
88
89 case WINED3DPT_TRIANGLEFAN:
90 return GL_TRIANGLE_FAN;
91
92 case WINED3DPT_LINELIST_ADJ:
93 return GL_LINES_ADJACENCY_ARB;
94
95 case WINED3DPT_LINESTRIP_ADJ:
96 return GL_LINE_STRIP_ADJACENCY_ARB;
97
98 case WINED3DPT_TRIANGLELIST_ADJ:
99 return GL_TRIANGLES_ADJACENCY_ARB;
100
101 case WINED3DPT_TRIANGLESTRIP_ADJ:
102 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
103
104 default:
105 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
106 return GL_NONE;
107 }
108}
109
110static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
111{
112 switch(primitive_type)
113 {
114 case GL_POINTS:
115 return WINED3DPT_POINTLIST;
116
117 case GL_LINES:
118 return WINED3DPT_LINELIST;
119
120 case GL_LINE_STRIP:
121 return WINED3DPT_LINESTRIP;
122
123 case GL_TRIANGLES:
124 return WINED3DPT_TRIANGLELIST;
125
126 case GL_TRIANGLE_STRIP:
127 return WINED3DPT_TRIANGLESTRIP;
128
129 case GL_TRIANGLE_FAN:
130 return WINED3DPT_TRIANGLEFAN;
131
132 case GL_LINES_ADJACENCY_ARB:
133 return WINED3DPT_LINELIST_ADJ;
134
135 case GL_LINE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_LINESTRIP_ADJ;
137
138 case GL_TRIANGLES_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLELIST_ADJ;
140
141 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
142 return WINED3DPT_TRIANGLESTRIP_ADJ;
143
144 default:
145 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
146 return WINED3DPT_UNDEFINED;
147 }
148}
149
150static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
151{
152 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
153 *regnum = WINED3D_FFP_POSITION;
154 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDWEIGHT;
156 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
157 *regnum = WINED3D_FFP_BLENDINDICES;
158 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
159 *regnum = WINED3D_FFP_NORMAL;
160 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
161 *regnum = WINED3D_FFP_PSIZE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
163 *regnum = WINED3D_FFP_DIFFUSE;
164 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
165 *regnum = WINED3D_FFP_SPECULAR;
166 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
167 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 else
169 {
170 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
171 *regnum = ~0U;
172 return FALSE;
173 }
174
175 return TRUE;
176}
177
178void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
179 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180{
181 /* We need to deal with frequency data! */
182 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
183 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
184 const DWORD *streams = declaration->streams;
185 unsigned int i;
186
187 memset(stream_info, 0, sizeof(*stream_info));
188
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
192
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
195 {
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
202
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
205
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
207
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
210 {
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 }
215 else
216 {
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
219
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
226 {
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 {
232 FIXME("System memory vertex data load offset is negative!\n");
233 }
234 }
235
236 if (fixup)
237 {
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 {
243 static BOOL warned = FALSE;
244 if (!warned)
245 {
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
249 }
250 }
251 }
252 }
253 data += element->offset;
254
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256
257 if (use_vshader)
258 {
259 if (element->output_slot == ~0U)
260 {
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
266 }
267 else
268 {
269 idx = element->output_slot;
270 stride_used = TRUE;
271 }
272 }
273 else
274 {
275 if (!element->ffp_valid)
276 {
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
280 }
281 else
282 {
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
284 }
285 }
286
287 if (stride_used)
288 {
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
300
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
302 {
303 stream_info->swizzle_map |= 1 << idx;
304 }
305 stream_info->use_map |= 1 << idx;
306 }
307 }
308
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
312 * own again.
313 *
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
315 * once in there. */
316 for (i = 0; i < stream_count; ++i)
317 {
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
320 }
321}
322
323static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
325{
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
330 e->stream_idx = 0;
331 e->buffer_object = 0;
332}
333
334void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
336{
337 unsigned int i;
338
339 memset(stream_info, 0, sizeof(*stream_info));
340
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
349
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
351 {
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
355 }
356
357 stream_info->position_transformed = strided->position_transformed;
358
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
360 {
361 if (!stream_info->elements[i].format_desc) continue;
362
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
364 {
365 stream_info->swizzle_map |= 1 << i;
366 }
367 stream_info->use_map |= 1 << i;
368 }
369}
370
371/**********************************************************
372 * IUnknown parts follows
373 **********************************************************/
374
375static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
376{
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
378
379 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
380 if (IsEqualGUID(riid, &IID_IUnknown)
381 || IsEqualGUID(riid, &IID_IWineD3DBase)
382 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
383 IUnknown_AddRef(iface);
384 *ppobj = This;
385 return S_OK;
386 }
387 *ppobj = NULL;
388 return E_NOINTERFACE;
389}
390
391static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 ULONG refCount = InterlockedIncrement(&This->ref);
394
395 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
396 return refCount;
397}
398
399static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
401 ULONG refCount = InterlockedDecrement(&This->ref);
402
403 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
404
405 if (!refCount) {
406 UINT i;
407
408 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
409 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
410 This->multistate_funcs[i] = NULL;
411 }
412
413 /* TODO: Clean up all the surfaces and textures! */
414 /* NOTE: You must release the parent if the object was created via a callback
415 ** ***************************/
416
417 if (!list_empty(&This->resources)) {
418 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
419 dumpResources(&This->resources);
420 }
421
422 if(This->contexts) ERR("Context array not freed!\n");
423 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
424 This->haveHardwareCursor = FALSE;
425
426 IWineD3D_Release(This->wineD3D);
427 This->wineD3D = NULL;
428 HeapFree(GetProcessHeap(), 0, This);
429 TRACE("Freed device %p\n", This);
430 This = NULL;
431 }
432 return refCount;
433}
434
435/**********************************************************
436 * IWineD3DDevice implementation follows
437 **********************************************************/
438static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 *pParent = This->parent;
441 IUnknown_AddRef(This->parent);
442 return WINED3D_OK;
443}
444
445static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
446 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
447{
448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
449 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
450 struct wined3d_buffer *object;
451 HRESULT hr;
452
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
454
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
456 if (!object)
457 {
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
460 }
461
462 object->vtbl = &wined3d_buffer_vtbl;
463 object->desc = *desc;
464
465 FIXME("Ignoring access flags (pool)\n");
466
467 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
468 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
469 if (FAILED(hr))
470 {
471 WARN("Failed to initialize resource, returning %#x\n", hr);
472 HeapFree(GetProcessHeap(), 0, object);
473 return hr;
474 }
475 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
476
477 TRACE("Created resource %p\n", object);
478
479 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
480 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
481
482 if (data)
483 {
484 BYTE *ptr;
485
486 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
487 if (FAILED(hr))
488 {
489 ERR("Failed to map buffer, hr %#x\n", hr);
490 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
491 return hr;
492 }
493
494 memcpy(ptr, data, desc->byte_width);
495
496 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
497 if (FAILED(hr))
498 {
499 ERR("Failed to unmap buffer, hr %#x\n", hr);
500 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
501 return hr;
502 }
503 }
504
505 *buffer = (IWineD3DBuffer *)object;
506
507 return WINED3D_OK;
508}
509
510static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
511 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
512{
513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
514 /* Dummy format for now */
515 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
516 struct wined3d_buffer *object;
517 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
518 HRESULT hr;
519 BOOL conv;
520
521 if(Size == 0) {
522 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
523 *ppVertexBuffer = NULL;
524 return WINED3DERR_INVALIDCALL;
525 } else if(Pool == WINED3DPOOL_SCRATCH) {
526 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
527 * anyway, SCRATCH vertex buffers aren't usable anywhere
528 */
529 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
530 *ppVertexBuffer = NULL;
531 return WINED3DERR_INVALIDCALL;
532 }
533
534 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
535 if (!object)
536 {
537 ERR("Out of memory\n");
538 *ppVertexBuffer = NULL;
539 return WINED3DERR_OUTOFVIDEOMEMORY;
540 }
541
542 object->vtbl = &wined3d_buffer_vtbl;
543 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
544 if (FAILED(hr))
545 {
546 WARN("Failed to initialize resource, returning %#x\n", hr);
547 HeapFree(GetProcessHeap(), 0, object);
548 *ppVertexBuffer = NULL;
549 return hr;
550 }
551 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
552
553 TRACE("(%p) : Created resource %p\n", This, object);
554
555 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);
556 *ppVertexBuffer = (IWineD3DBuffer *)object;
557
558 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
559 * drawStridedFast (half-life 2).
560 *
561 * Basically converting the vertices in the buffer is quite expensive, and observations
562 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
563 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
564 *
565 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
566 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
567 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
568 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
569 * dx7 apps.
570 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
571 * more. In this call we can convert dx7 buffers too.
572 */
573 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
574 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
575 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
576 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
577 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
578 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
579 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
580 } else if(dxVersion <= 7 && conv) {
581 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
582 } else {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
584 }
585 return WINED3D_OK;
586}
587
588static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
589 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
590{
591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
592 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
593 struct wined3d_buffer *object;
594 HRESULT hr;
595
596 TRACE("(%p) Creating index buffer\n", This);
597
598 /* Allocate the storage for the device */
599 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
600 if (!object)
601 {
602 ERR("Out of memory\n");
603 *ppIndexBuffer = NULL;
604 return WINED3DERR_OUTOFVIDEOMEMORY;
605 }
606
607 object->vtbl = &wined3d_buffer_vtbl;
608 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
609 if (FAILED(hr))
610 {
611 WARN("Failed to initialize resource, returning %#x\n", hr);
612 HeapFree(GetProcessHeap(), 0, object);
613 *ppIndexBuffer = NULL;
614 return hr;
615 }
616 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
617
618 TRACE("(%p) : Created resource %p\n", This, object);
619
620 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
621 object->flags |= WINED3D_BUFFER_CREATEBO;
622 }
623
624 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
625 Pool, object, object->resource.allocatedMemory);
626 *ppIndexBuffer = (IWineD3DBuffer *) object;
627
628 return WINED3D_OK;
629}
630
631static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
632
633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
634 IWineD3DStateBlockImpl *object;
635 unsigned int i, j;
636 HRESULT temp_result;
637
638 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
639 if(!object)
640 {
641 ERR("Out of memory\n");
642 *ppStateBlock = NULL;
643 return WINED3DERR_OUTOFVIDEOMEMORY;
644 }
645
646 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
647 object->wineD3DDevice = This;
648 object->parent = parent;
649 object->ref = 1;
650 object->blockType = Type;
651
652 *ppStateBlock = (IWineD3DStateBlock *)object;
653
654 for(i = 0; i < LIGHTMAP_SIZE; i++) {
655 list_init(&object->lightMap[i]);
656 }
657
658 temp_result = allocate_shader_constants(object);
659 if (FAILED(temp_result))
660 {
661 HeapFree(GetProcessHeap(), 0, object);
662 return temp_result;
663 }
664
665 /* Special case - Used during initialization to produce a placeholder stateblock
666 so other functions called can update a state block */
667 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
668 {
669 /* Don't bother increasing the reference count otherwise a device will never
670 be freed due to circular dependencies */
671 return WINED3D_OK;
672 }
673
674 /* Otherwise, might as well set the whole state block to the appropriate values */
675 if (This->stateBlock != NULL)
676 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
677 else
678 memset(object->streamFreq, 1, sizeof(object->streamFreq));
679
680 /* Reset the ref and type after kludging it */
681 object->wineD3DDevice = This;
682 object->ref = 1;
683 object->blockType = Type;
684
685 TRACE("Updating changed flags appropriate for type %d\n", Type);
686
687 if (Type == WINED3DSBT_ALL) {
688
689 TRACE("ALL => Pretend everything has changed\n");
690 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
691
692 /* Lights are not part of the changed / set structure */
693 for(j = 0; j < LIGHTMAP_SIZE; j++) {
694 struct list *e;
695 LIST_FOR_EACH(e, &object->lightMap[j]) {
696 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
697 light->changed = TRUE;
698 light->enabledChanged = TRUE;
699 }
700 }
701 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
702 object->contained_render_states[j - 1] = j;
703 }
704 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
705 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
706 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
707 object->contained_transform_states[j - 1] = j;
708 }
709 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
710 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
711 object->contained_vs_consts_f[j] = j;
712 }
713 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
714 for(j = 0; j < MAX_CONST_I; j++) {
715 object->contained_vs_consts_i[j] = j;
716 }
717 object->num_contained_vs_consts_i = MAX_CONST_I;
718 for(j = 0; j < MAX_CONST_B; j++) {
719 object->contained_vs_consts_b[j] = j;
720 }
721 object->num_contained_vs_consts_b = MAX_CONST_B;
722 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
723 object->contained_ps_consts_f[j] = j;
724 }
725 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
726 for(j = 0; j < MAX_CONST_I; j++) {
727 object->contained_ps_consts_i[j] = j;
728 }
729 object->num_contained_ps_consts_i = MAX_CONST_I;
730 for(j = 0; j < MAX_CONST_B; j++) {
731 object->contained_ps_consts_b[j] = j;
732 }
733 object->num_contained_ps_consts_b = MAX_CONST_B;
734 for(i = 0; i < MAX_TEXTURES; i++) {
735 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
736 {
737 object->contained_tss_states[object->num_contained_tss_states].stage = i;
738 object->contained_tss_states[object->num_contained_tss_states].state = j;
739 object->num_contained_tss_states++;
740 }
741 }
742 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
743 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
744 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
745 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
746 object->num_contained_sampler_states++;
747 }
748 }
749
750 for(i = 0; i < MAX_STREAMS; i++) {
751 if(object->streamSource[i]) {
752 IWineD3DBuffer_AddRef(object->streamSource[i]);
753 }
754 }
755 if(object->pIndexData) {
756 IWineD3DBuffer_AddRef(object->pIndexData);
757 }
758 if(object->vertexShader) {
759 IWineD3DVertexShader_AddRef(object->vertexShader);
760 }
761 if(object->pixelShader) {
762 IWineD3DPixelShader_AddRef(object->pixelShader);
763 }
764
765 } else if (Type == WINED3DSBT_PIXELSTATE) {
766
767 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
768 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
769
770 object->changed.pixelShader = TRUE;
771
772 /* Pixel Shader Constants */
773 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
774 object->contained_ps_consts_f[i] = i;
775 object->changed.pixelShaderConstantsF[i] = TRUE;
776 }
777 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
778 for (i = 0; i < MAX_CONST_B; ++i) {
779 object->contained_ps_consts_b[i] = i;
780 object->changed.pixelShaderConstantsB |= (1 << i);
781 }
782 object->num_contained_ps_consts_b = MAX_CONST_B;
783 for (i = 0; i < MAX_CONST_I; ++i) {
784 object->contained_ps_consts_i[i] = i;
785 object->changed.pixelShaderConstantsI |= (1 << i);
786 }
787 object->num_contained_ps_consts_i = MAX_CONST_I;
788
789 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
790 DWORD rs = SavedPixelStates_R[i];
791 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
792 object->contained_render_states[i] = rs;
793 }
794 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
795 for (j = 0; j < MAX_TEXTURES; j++) {
796 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
797 DWORD state = SavedPixelStates_T[i];
798 object->changed.textureState[j] |= 1 << state;
799 object->contained_tss_states[object->num_contained_tss_states].stage = j;
800 object->contained_tss_states[object->num_contained_tss_states].state = state;
801 object->num_contained_tss_states++;
802 }
803 }
804 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
805 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
806 DWORD state = SavedPixelStates_S[i];
807 object->changed.samplerState[j] |= 1 << state;
808 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
809 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
810 object->num_contained_sampler_states++;
811 }
812 }
813 if(object->pixelShader) {
814 IWineD3DPixelShader_AddRef(object->pixelShader);
815 }
816
817 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
818 * on them. This makes releasing the buffer easier
819 */
820 for(i = 0; i < MAX_STREAMS; i++) {
821 object->streamSource[i] = NULL;
822 }
823 object->pIndexData = NULL;
824 object->vertexShader = NULL;
825
826 } else if (Type == WINED3DSBT_VERTEXSTATE) {
827
828 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
829 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
830
831 object->changed.vertexShader = TRUE;
832
833 /* Vertex Shader Constants */
834 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
835 object->changed.vertexShaderConstantsF[i] = TRUE;
836 object->contained_vs_consts_f[i] = i;
837 }
838 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
839 for (i = 0; i < MAX_CONST_B; ++i) {
840 object->contained_vs_consts_b[i] = i;
841 object->changed.vertexShaderConstantsB |= (1 << i);
842 }
843 object->num_contained_vs_consts_b = MAX_CONST_B;
844 for (i = 0; i < MAX_CONST_I; ++i) {
845 object->contained_vs_consts_i[i] = i;
846 object->changed.vertexShaderConstantsI |= (1 << i);
847 }
848 object->num_contained_vs_consts_i = MAX_CONST_I;
849 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
850 DWORD rs = SavedVertexStates_R[i];
851 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
852 object->contained_render_states[i] = rs;
853 }
854 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
855 for (j = 0; j < MAX_TEXTURES; j++) {
856 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
857 DWORD state = SavedVertexStates_T[i];
858 object->changed.textureState[j] |= 1 << state;
859 object->contained_tss_states[object->num_contained_tss_states].stage = j;
860 object->contained_tss_states[object->num_contained_tss_states].state = state;
861 object->num_contained_tss_states++;
862 }
863 }
864 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
865 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
866 DWORD state = SavedVertexStates_S[i];
867 object->changed.samplerState[j] |= 1 << state;
868 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
869 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
870 object->num_contained_sampler_states++;
871 }
872 }
873
874 for(j = 0; j < LIGHTMAP_SIZE; j++) {
875 struct list *e;
876 LIST_FOR_EACH(e, &object->lightMap[j]) {
877 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
878 light->changed = TRUE;
879 light->enabledChanged = TRUE;
880 }
881 }
882
883 for(i = 0; i < MAX_STREAMS; i++) {
884 if(object->streamSource[i]) {
885 IWineD3DBuffer_AddRef(object->streamSource[i]);
886 }
887 }
888 if(object->vertexShader) {
889 IWineD3DVertexShader_AddRef(object->vertexShader);
890 }
891 object->pIndexData = NULL;
892 object->pixelShader = NULL;
893 } else {
894 FIXME("Unrecognized state block type %d\n", Type);
895 }
896
897 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
898 return WINED3D_OK;
899}
900
901static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
902 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
903 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
904 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
905{
906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
907 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
908 unsigned int Size = 1;
909 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
910 UINT mul_4w, mul_4h;
911 HRESULT hr;
912
913 TRACE("(%p) Create surface\n",This);
914
915 if(MultisampleQuality > 0) {
916 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
917 MultisampleQuality=0;
918 }
919
920 /** FIXME: Check that the format is supported
921 * by the device.
922 *******************************/
923
924 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
925 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
926 * space!
927 *********************************/
928 mul_4w = (Width + 3) & ~3;
929 mul_4h = (Height + 3) & ~3;
930 if (WINED3DFMT_UNKNOWN == Format) {
931 Size = 0;
932 } else if (Format == WINED3DFMT_DXT1) {
933 /* DXT1 is half byte per pixel */
934 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
935
936 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
937 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
938 Format == WINED3DFMT_ATI2N) {
939 Size = (mul_4w * glDesc->byte_count * mul_4h);
940 } else {
941 /* The pitch is a multiple of 4 bytes */
942 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
943 Size *= Height;
944 }
945
946 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
947
948 /** Create and initialise the surface resource **/
949 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
950 if (!object)
951 {
952 ERR("Out of memory\n");
953 *ppSurface = NULL;
954 return WINED3DERR_OUTOFVIDEOMEMORY;
955 }
956
957 /* Look at the implementation and set the correct Vtable */
958 switch(Impl)
959 {
960 case SURFACE_OPENGL:
961 /* Check if a 3D adapter is available when creating gl surfaces */
962 if (!This->adapter)
963 {
964 ERR("OpenGL surfaces are not available without opengl\n");
965 HeapFree(GetProcessHeap(), 0, object);
966 return WINED3DERR_NOTAVAILABLE;
967 }
968 object->lpVtbl = &IWineD3DSurface_Vtbl;
969 break;
970
971 case SURFACE_GDI:
972 object->lpVtbl = &IWineGDISurface_Vtbl;
973 break;
974
975 default:
976 /* To be sure to catch this */
977 ERR("Unknown requested surface implementation %d!\n", Impl);
978 HeapFree(GetProcessHeap(), 0, object);
979 return WINED3DERR_INVALIDCALL;
980 }
981
982 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
983 if (FAILED(hr))
984 {
985 WARN("Failed to initialize resource, returning %#x\n", hr);
986 HeapFree(GetProcessHeap(), 0, object);
987 *ppSurface = NULL;
988 return hr;
989 }
990
991 TRACE("(%p) : Created resource %p\n", This, object);
992
993 *ppSurface = (IWineD3DSurface *)object;
994
995 /* "Standalone" surface */
996 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
997
998 object->currentDesc.Width = Width;
999 object->currentDesc.Height = Height;
1000 object->currentDesc.MultiSampleType = MultiSample;
1001 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1002 object->glDescription.level = Level;
1003 list_init(&object->overlays);
1004
1005 /* Flags */
1006 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1007 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1008 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1009 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1010
1011 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1012
1013 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1014 * this function is too deep to need to care about things like this.
1015 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1016 * ****************************************/
1017 switch(Pool) {
1018 case WINED3DPOOL_SCRATCH:
1019 if(!Lockable)
1020 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1021 "which are mutually exclusive, setting lockable to TRUE\n");
1022 Lockable = TRUE;
1023 break;
1024 case WINED3DPOOL_SYSTEMMEM:
1025 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1026 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1027 case WINED3DPOOL_MANAGED:
1028 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1029 "Usage of DYNAMIC which are mutually exclusive, not doing "
1030 "anything just telling you.\n");
1031 break;
1032 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1033 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1034 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1035 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1036 break;
1037 default:
1038 FIXME("(%p) Unknown pool %d\n", This, Pool);
1039 break;
1040 };
1041
1042 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1043 FIXME("Trying to create a render target that isn't in the default pool\n");
1044 }
1045
1046 /* mark the texture as dirty so that it gets loaded first time around*/
1047 surface_add_dirty_rect(*ppSurface, NULL);
1048 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1049 This, Width, Height, Format, debug_d3dformat(Format),
1050 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1051
1052 list_init(&object->renderbuffers);
1053
1054 /* Call the private setup routine */
1055 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1056 if (FAILED(hr))
1057 {
1058 ERR("Private setup failed, returning %#x\n", hr);
1059 IWineD3DSurface_Release(*ppSurface);
1060 *ppSurface = NULL;
1061 return hr;
1062 }
1063
1064 return hr;
1065}
1066
1067static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1068 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1069{
1070 struct wined3d_rendertarget_view *object;
1071
1072 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1073 if (!object)
1074 {
1075 ERR("Failed to allocate memory\n");
1076 return E_OUTOFMEMORY;
1077 }
1078
1079 object->vtbl = &wined3d_rendertarget_view_vtbl;
1080 object->refcount = 1;
1081 IWineD3DResource_AddRef(resource);
1082 object->resource = resource;
1083 object->parent = parent;
1084
1085 *rendertarget_view = (IWineD3DRendertargetView *)object;
1086
1087 return WINED3D_OK;
1088}
1089
1090static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1091 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1092 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1093{
1094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1095 IWineD3DTextureImpl *object;
1096 HRESULT hr;
1097
1098 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1099 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1100 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1101
1102 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1103 if (!object)
1104 {
1105 ERR("Out of memory\n");
1106 *ppTexture = NULL;
1107 return WINED3DERR_OUTOFVIDEOMEMORY;
1108 }
1109
1110 object->lpVtbl = &IWineD3DTexture_Vtbl;
1111
1112 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
1113 if (FAILED(hr))
1114 {
1115 WARN("Failed to initialize texture, returning %#x\n", hr);
1116 HeapFree(GetProcessHeap(), 0, object);
1117 *ppTexture = NULL;
1118 return hr;
1119 }
1120
1121 *ppTexture = (IWineD3DTexture *)object;
1122
1123 TRACE("(%p) : Created texture %p\n", This, object);
1124
1125 return WINED3D_OK;
1126}
1127
1128static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1129 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1130 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1131{
1132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1133 IWineD3DVolumeTextureImpl *object;
1134 HRESULT hr;
1135
1136 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1137 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1138
1139 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1140 if (!object)
1141 {
1142 ERR("Out of memory\n");
1143 *ppVolumeTexture = NULL;
1144 return WINED3DERR_OUTOFVIDEOMEMORY;
1145 }
1146
1147 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1148 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1149 if (FAILED(hr))
1150 {
1151 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1152 HeapFree(GetProcessHeap(), 0, object);
1153 *ppVolumeTexture = NULL;
1154 return hr;
1155 }
1156
1157 TRACE("(%p) : Created volume texture %p.\n", This, object);
1158 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1159
1160 return WINED3D_OK;
1161}
1162
1163static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1164 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1165 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1166{
1167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1168 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1169 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1170 HRESULT hr;
1171
1172 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1173 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1174 return WINED3DERR_INVALIDCALL;
1175 }
1176
1177 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1178 if (!object)
1179 {
1180 ERR("Out of memory\n");
1181 *ppVolume = NULL;
1182 return WINED3DERR_OUTOFVIDEOMEMORY;
1183 }
1184
1185 object->lpVtbl = &IWineD3DVolume_Vtbl;
1186 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1187 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1188 if (FAILED(hr))
1189 {
1190 WARN("Failed to initialize resource, returning %#x\n", hr);
1191 HeapFree(GetProcessHeap(), 0, object);
1192 *ppVolume = NULL;
1193 return hr;
1194 }
1195
1196 TRACE("(%p) : Created resource %p\n", This, object);
1197
1198 *ppVolume = (IWineD3DVolume *)object;
1199
1200 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1201 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1202
1203 object->currentDesc.Width = Width;
1204 object->currentDesc.Height = Height;
1205 object->currentDesc.Depth = Depth;
1206
1207 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1208 object->lockable = TRUE;
1209 object->locked = FALSE;
1210 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1211 object->dirty = TRUE;
1212
1213 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1214
1215 return WINED3D_OK;
1216}
1217
1218static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1219 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1220 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1221{
1222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1223 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1224 HRESULT hr;
1225
1226 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1227 if (!object)
1228 {
1229 ERR("Out of memory\n");
1230 *ppCubeTexture = NULL;
1231 return WINED3DERR_OUTOFVIDEOMEMORY;
1232 }
1233
1234 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1235 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1236 if (FAILED(hr))
1237 {
1238 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1239 HeapFree(GetProcessHeap(), 0, object);
1240 *ppCubeTexture = NULL;
1241 return hr;
1242 }
1243
1244 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1245 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1246
1247 return WINED3D_OK;
1248}
1249
1250static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1252 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1253 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1254 const IWineD3DQueryVtbl *vtable;
1255
1256 /* Just a check to see if we support this type of query */
1257 switch(Type) {
1258 case WINED3DQUERYTYPE_OCCLUSION:
1259 TRACE("(%p) occlusion query\n", This);
1260 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1261 hr = WINED3D_OK;
1262 else
1263 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1264
1265 vtable = &IWineD3DOcclusionQuery_Vtbl;
1266 break;
1267
1268 case WINED3DQUERYTYPE_EVENT:
1269 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1270 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1271 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1272 */
1273 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1274 }
1275 vtable = &IWineD3DEventQuery_Vtbl;
1276 hr = WINED3D_OK;
1277 break;
1278
1279 case WINED3DQUERYTYPE_VCACHE:
1280 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1281 case WINED3DQUERYTYPE_VERTEXSTATS:
1282 case WINED3DQUERYTYPE_TIMESTAMP:
1283 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1284 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1285 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1286 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1287 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1288 case WINED3DQUERYTYPE_PIXELTIMINGS:
1289 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1290 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1291 default:
1292 /* Use the base Query vtable until we have a special one for each query */
1293 vtable = &IWineD3DQuery_Vtbl;
1294 FIXME("(%p) Unhandled query type %d\n", This, Type);
1295 }
1296 if(NULL == ppQuery || hr != WINED3D_OK) {
1297 return hr;
1298 }
1299
1300 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1301 if(!object)
1302 {
1303 ERR("Out of memory\n");
1304 *ppQuery = NULL;
1305 return WINED3DERR_OUTOFVIDEOMEMORY;
1306 }
1307
1308 object->lpVtbl = vtable;
1309 object->type = Type;
1310 object->state = QUERY_CREATED;
1311 object->wineD3DDevice = This;
1312 object->parent = parent;
1313 object->ref = 1;
1314
1315 *ppQuery = (IWineD3DQuery *)object;
1316
1317 /* allocated the 'extended' data based on the type of query requested */
1318 switch(Type){
1319 case WINED3DQUERYTYPE_OCCLUSION:
1320 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1321 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1322
1323 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1324 TRACE("(%p) Allocating data for an occlusion query\n", This);
1325
1326 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1327 ENTER_GL();
1328 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1329 LEAVE_GL();
1330 break;
1331 }
1332 case WINED3DQUERYTYPE_EVENT:
1333 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1334 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1335
1336 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1337 ENTER_GL();
1338 if(GL_SUPPORT(APPLE_FENCE)) {
1339 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1340 checkGLcall("glGenFencesAPPLE");
1341 } else if(GL_SUPPORT(NV_FENCE)) {
1342 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1343 checkGLcall("glGenFencesNV");
1344 }
1345 LEAVE_GL();
1346 break;
1347
1348 case WINED3DQUERYTYPE_VCACHE:
1349 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1350 case WINED3DQUERYTYPE_VERTEXSTATS:
1351 case WINED3DQUERYTYPE_TIMESTAMP:
1352 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1353 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1354 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1355 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1356 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1357 case WINED3DQUERYTYPE_PIXELTIMINGS:
1358 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1359 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1360 default:
1361 object->extendedData = 0;
1362 FIXME("(%p) Unhandled query type %d\n",This , Type);
1363 }
1364 TRACE("(%p) : Created Query %p\n", This, object);
1365 return WINED3D_OK;
1366}
1367
1368/*****************************************************************************
1369 * IWineD3DDeviceImpl_SetupFullscreenWindow
1370 *
1371 * Helper function that modifies a HWND's Style and ExStyle for proper
1372 * fullscreen use.
1373 *
1374 * Params:
1375 * iface: Pointer to the IWineD3DDevice interface
1376 * window: Window to setup
1377 *
1378 *****************************************************************************/
1379static LONG fullscreen_style(LONG orig_style) {
1380 LONG style = orig_style;
1381 style &= ~WS_CAPTION;
1382 style &= ~WS_THICKFRAME;
1383
1384 /* Make sure the window is managed, otherwise we won't get keyboard input */
1385 style |= WS_POPUP | WS_SYSMENU;
1386
1387 return style;
1388}
1389
1390static LONG fullscreen_exStyle(LONG orig_exStyle) {
1391 LONG exStyle = orig_exStyle;
1392
1393 /* Filter out window decorations */
1394 exStyle &= ~WS_EX_WINDOWEDGE;
1395 exStyle &= ~WS_EX_CLIENTEDGE;
1396
1397 return exStyle;
1398}
1399
1400static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402
1403 LONG style, exStyle;
1404 /* Don't do anything if an original style is stored.
1405 * That shouldn't happen
1406 */
1407 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1408 if (This->style || This->exStyle) {
1409 ERR("(%p): Want to change the window parameters of HWND %p, but "
1410 "another style is stored for restoration afterwards\n", This, window);
1411 }
1412
1413 /* Get the parameters and save them */
1414 style = GetWindowLongW(window, GWL_STYLE);
1415 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1416 This->style = style;
1417 This->exStyle = exStyle;
1418
1419 style = fullscreen_style(style);
1420 exStyle = fullscreen_exStyle(exStyle);
1421
1422 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1423 This->style, This->exStyle, style, exStyle);
1424
1425 SetWindowLongW(window, GWL_STYLE, style);
1426 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1427
1428 /* Inform the window about the update. */
1429 SetWindowPos(window, HWND_TOP, 0, 0,
1430 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1431}
1432
1433/*****************************************************************************
1434 * IWineD3DDeviceImpl_RestoreWindow
1435 *
1436 * Helper function that restores a windows' properties when taking it out
1437 * of fullscreen mode
1438 *
1439 * Params:
1440 * iface: Pointer to the IWineD3DDevice interface
1441 * window: Window to setup
1442 *
1443 *****************************************************************************/
1444static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1446 LONG style, exStyle;
1447
1448 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1449 * switch, do nothing
1450 */
1451 if (!This->style && !This->exStyle) return;
1452
1453 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1454 This, window, This->style, This->exStyle);
1455
1456 style = GetWindowLongW(window, GWL_STYLE);
1457 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1458
1459 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1460 * Some applications change it before calling Reset() when switching between windowed and
1461 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1462 */
1463 if(style == fullscreen_style(This->style) &&
1464 exStyle == fullscreen_style(This->exStyle)) {
1465 SetWindowLongW(window, GWL_STYLE, This->style);
1466 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1467 }
1468
1469 /* Delete the old values */
1470 This->style = 0;
1471 This->exStyle = 0;
1472
1473 /* Inform the window about the update */
1474 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1475 0, 0, 0, 0, /* Pos, Size, ignored */
1476 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1477}
1478
1479/* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1480static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1481 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1482 IUnknown *parent, WINED3DSURFTYPE surface_type)
1483{
1484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1485
1486 HDC hDc;
1487 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1488 HRESULT hr;
1489 IUnknown *bufferParent;
1490 BOOL displaymode_set = FALSE;
1491 WINED3DDISPLAYMODE Mode;
1492 const struct GlPixelFormatDesc *format_desc;
1493
1494 TRACE("(%p) : Created Additional Swap Chain\n", This);
1495
1496 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1497 * does a device hold a reference to a swap chain giving them a lifetime of the device
1498 * or does the swap chain notify the device of its destruction.
1499 *******************************/
1500
1501 /* Check the params */
1502 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1503 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1504 return WINED3DERR_INVALIDCALL;
1505 } else if (pPresentationParameters->BackBufferCount > 1) {
1506 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");
1507 }
1508
1509 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1510 if(!object)
1511 {
1512 ERR("Out of memory\n");
1513 *ppSwapChain = NULL;
1514 return WINED3DERR_OUTOFVIDEOMEMORY;
1515 }
1516
1517 switch(surface_type) {
1518 case SURFACE_GDI:
1519 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1520 break;
1521 case SURFACE_OPENGL:
1522 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1523 break;
1524 case SURFACE_UNKNOWN:
1525 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1526 HeapFree(GetProcessHeap(), 0, object);
1527 return WINED3DERR_INVALIDCALL;
1528 }
1529 object->wineD3DDevice = This;
1530 object->parent = parent;
1531 object->ref = 1;
1532
1533 *ppSwapChain = (IWineD3DSwapChain *)object;
1534
1535 /*********************
1536 * Lookup the window Handle and the relating X window handle
1537 ********************/
1538
1539 /* Setup hwnd we are using, plus which display this equates to */
1540 object->win_handle = pPresentationParameters->hDeviceWindow;
1541 if (!object->win_handle) {
1542 object->win_handle = This->createParms.hFocusWindow;
1543 }
1544 if(!pPresentationParameters->Windowed && object->win_handle) {
1545 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1546 pPresentationParameters->BackBufferWidth,
1547 pPresentationParameters->BackBufferHeight);
1548 }
1549
1550 hDc = GetDC(object->win_handle);
1551 TRACE("Using hDc %p\n", hDc);
1552
1553 if (NULL == hDc) {
1554 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1555 return WINED3DERR_NOTAVAILABLE;
1556 }
1557
1558 /* Get info on the current display setup */
1559 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1560 object->orig_width = Mode.Width;
1561 object->orig_height = Mode.Height;
1562 object->orig_fmt = Mode.Format;
1563 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1564
1565 if (pPresentationParameters->Windowed &&
1566 ((pPresentationParameters->BackBufferWidth == 0) ||
1567 (pPresentationParameters->BackBufferHeight == 0) ||
1568 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1569
1570 RECT Rect;
1571 GetClientRect(object->win_handle, &Rect);
1572
1573 if (pPresentationParameters->BackBufferWidth == 0) {
1574 pPresentationParameters->BackBufferWidth = Rect.right;
1575 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1576 }
1577 if (pPresentationParameters->BackBufferHeight == 0) {
1578 pPresentationParameters->BackBufferHeight = Rect.bottom;
1579 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1580 }
1581 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1582 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1583 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1584 }
1585 }
1586
1587 /* Put the correct figures in the presentation parameters */
1588 TRACE("Copying across presentation parameters\n");
1589 object->presentParms = *pPresentationParameters;
1590
1591 TRACE("calling rendertarget CB\n");
1592 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1593 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1594 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1595 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1596 if (SUCCEEDED(hr)) {
1597 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1598 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1599 if(surface_type == SURFACE_OPENGL) {
1600 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1601 }
1602 } else {
1603 ERR("Failed to create the front buffer\n");
1604 goto error;
1605 }
1606
1607 /*********************
1608 * Windowed / Fullscreen
1609 *******************/
1610
1611 /**
1612 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1613 * so we should really check to see if there is a fullscreen swapchain already
1614 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1615 **************************************/
1616
1617 if (!pPresentationParameters->Windowed) {
1618 WINED3DDISPLAYMODE mode;
1619
1620
1621 /* Change the display settings */
1622 mode.Width = pPresentationParameters->BackBufferWidth;
1623 mode.Height = pPresentationParameters->BackBufferHeight;
1624 mode.Format = pPresentationParameters->BackBufferFormat;
1625 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1626
1627 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1628 displaymode_set = TRUE;
1629 }
1630
1631 /**
1632 * Create an opengl context for the display visual
1633 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1634 * use different properties after that point in time. FIXME: How to handle when requested format
1635 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1636 * it chooses is identical to the one already being used!
1637 **********************************/
1638 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1639
1640 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1641 if(!object->context) {
1642 ERR("Failed to create the context array\n");
1643 hr = E_OUTOFMEMORY;
1644 goto error;
1645 }
1646 object->num_contexts = 1;
1647
1648 if(surface_type == SURFACE_OPENGL) {
1649 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1650 if (!object->context[0]) {
1651 ERR("Failed to create a new context\n");
1652 hr = WINED3DERR_NOTAVAILABLE;
1653 goto error;
1654 } else {
1655 TRACE("Context created (HWND=%p, glContext=%p)\n",
1656 object->win_handle, object->context[0]->glCtx);
1657 }
1658 }
1659
1660 /*********************
1661 * Create the back, front and stencil buffers
1662 *******************/
1663 if(object->presentParms.BackBufferCount > 0) {
1664 UINT i;
1665
1666 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1667 if(!object->backBuffer) {
1668 ERR("Out of memory\n");
1669 hr = E_OUTOFMEMORY;
1670 goto error;
1671 }
1672
1673 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1674 TRACE("calling rendertarget CB\n");
1675 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1676 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1677 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1678 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1679 if(SUCCEEDED(hr)) {
1680 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1681 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1682 } else {
1683 ERR("Cannot create new back buffer\n");
1684 goto error;
1685 }
1686 if(surface_type == SURFACE_OPENGL) {
1687 ENTER_GL();
1688 glDrawBuffer(GL_BACK);
1689 checkGLcall("glDrawBuffer(GL_BACK)");
1690 LEAVE_GL();
1691 }
1692 }
1693 } else {
1694 object->backBuffer = NULL;
1695
1696 /* Single buffering - draw to front buffer */
1697 if(surface_type == SURFACE_OPENGL) {
1698 ENTER_GL();
1699 glDrawBuffer(GL_FRONT);
1700 checkGLcall("glDrawBuffer(GL_FRONT)");
1701 LEAVE_GL();
1702 }
1703 }
1704
1705 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1706 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1707 TRACE("Creating depth stencil buffer\n");
1708 if (This->auto_depth_stencil_buffer == NULL ) {
1709 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1710 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1711 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1712 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1713 &This->auto_depth_stencil_buffer);
1714 if (SUCCEEDED(hr)) {
1715 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1716 } else {
1717 ERR("Failed to create the auto depth stencil\n");
1718 goto error;
1719 }
1720 }
1721 }
1722
1723 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1724
1725 TRACE("Created swapchain %p\n", object);
1726 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1727 return WINED3D_OK;
1728
1729error:
1730 if (displaymode_set) {
1731 DEVMODEW devmode;
1732 RECT clip_rc;
1733
1734 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1735 ClipCursor(NULL);
1736
1737 /* Change the display settings */
1738 memset(&devmode, 0, sizeof(devmode));
1739 devmode.dmSize = sizeof(devmode);
1740 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1741 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1742 devmode.dmPelsWidth = object->orig_width;
1743 devmode.dmPelsHeight = object->orig_height;
1744 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1745 }
1746
1747 if (object->backBuffer) {
1748 UINT i;
1749 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1750 if(object->backBuffer[i]) {
1751 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1752 IUnknown_Release(bufferParent); /* once for the get parent */
1753 if (IUnknown_Release(bufferParent) > 0) {
1754 FIXME("(%p) Something's still holding the back buffer\n",This);
1755 }
1756 }
1757 }
1758 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1759 object->backBuffer = NULL;
1760 }
1761 if(object->context && object->context[0])
1762 DestroyContext(This, object->context[0]);
1763 if(object->frontBuffer) {
1764 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1765 IUnknown_Release(bufferParent); /* once for the get parent */
1766 if (IUnknown_Release(bufferParent) > 0) {
1767 FIXME("(%p) Something's still holding the front buffer\n",This);
1768 }
1769 }
1770 HeapFree(GetProcessHeap(), 0, object);
1771 return hr;
1772}
1773
1774/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1775static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1777 TRACE("(%p)\n", This);
1778
1779 return This->NumberOfSwapChains;
1780}
1781
1782static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1784 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1785
1786 if(iSwapChain < This->NumberOfSwapChains) {
1787 *pSwapChain = This->swapchains[iSwapChain];
1788 IWineD3DSwapChain_AddRef(*pSwapChain);
1789 TRACE("(%p) returning %p\n", This, *pSwapChain);
1790 return WINED3D_OK;
1791 } else {
1792 TRACE("Swapchain out of range\n");
1793 *pSwapChain = NULL;
1794 return WINED3DERR_INVALIDCALL;
1795 }
1796}
1797
1798/*****
1799 * Vertex Declaration
1800 *****/
1801static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1802 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1804 IWineD3DVertexDeclarationImpl *object = NULL;
1805 HRESULT hr = WINED3D_OK;
1806
1807 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1808 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1809
1810 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1811 if(!object)
1812 {
1813 ERR("Out of memory\n");
1814 *ppVertexDeclaration = NULL;
1815 return WINED3DERR_OUTOFVIDEOMEMORY;
1816 }
1817
1818 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1819 object->wineD3DDevice = This;
1820 object->parent = parent;
1821 object->ref = 1;
1822
1823 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1824
1825 hr = vertexdeclaration_init(object, elements, element_count);
1826
1827 if(FAILED(hr)) {
1828 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1829 *ppVertexDeclaration = NULL;
1830 }
1831
1832 return hr;
1833}
1834
1835static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1836 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1837
1838 unsigned int idx, idx2;
1839 unsigned int offset;
1840 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1841 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1842 BOOL has_blend_idx = has_blend &&
1843 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1844 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1845 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1846 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1847 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1848 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1849 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1850
1851 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1852 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1853 WINED3DVERTEXELEMENT *elements = NULL;
1854
1855 unsigned int size;
1856 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1857 if (has_blend_idx) num_blends--;
1858
1859 /* Compute declaration size */
1860 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1861 has_psize + has_diffuse + has_specular + num_textures;
1862
1863 /* convert the declaration */
1864 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1865 if (!elements) return ~0U;
1866
1867 idx = 0;
1868 if (has_pos) {
1869 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1870 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1871 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1872 }
1873 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1874 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1875 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1876 }
1877 else {
1878 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1879 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1880 }
1881 elements[idx].usage_idx = 0;
1882 idx++;
1883 }
1884 if (has_blend && (num_blends > 0)) {
1885 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1886 elements[idx].format = WINED3DFMT_A8R8G8B8;
1887 else {
1888 switch(num_blends) {
1889 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1890 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1891 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1892 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1893 default:
1894 ERR("Unexpected amount of blend values: %u\n", num_blends);
1895 }
1896 }
1897 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1898 elements[idx].usage_idx = 0;
1899 idx++;
1900 }
1901 if (has_blend_idx) {
1902 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1903 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1904 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1905 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1906 elements[idx].format = WINED3DFMT_A8R8G8B8;
1907 else
1908 elements[idx].format = WINED3DFMT_R32_FLOAT;
1909 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1910 elements[idx].usage_idx = 0;
1911 idx++;
1912 }
1913 if (has_normal) {
1914 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1915 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1916 elements[idx].usage_idx = 0;
1917 idx++;
1918 }
1919 if (has_psize) {
1920 elements[idx].format = WINED3DFMT_R32_FLOAT;
1921 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1922 elements[idx].usage_idx = 0;
1923 idx++;
1924 }
1925 if (has_diffuse) {
1926 elements[idx].format = WINED3DFMT_A8R8G8B8;
1927 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1928 elements[idx].usage_idx = 0;
1929 idx++;
1930 }
1931 if (has_specular) {
1932 elements[idx].format = WINED3DFMT_A8R8G8B8;
1933 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1934 elements[idx].usage_idx = 1;
1935 idx++;
1936 }
1937 for (idx2 = 0; idx2 < num_textures; idx2++) {
1938 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1939 switch (numcoords) {
1940 case WINED3DFVF_TEXTUREFORMAT1:
1941 elements[idx].format = WINED3DFMT_R32_FLOAT;
1942 break;
1943 case WINED3DFVF_TEXTUREFORMAT2:
1944 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1945 break;
1946 case WINED3DFVF_TEXTUREFORMAT3:
1947 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1948 break;
1949 case WINED3DFVF_TEXTUREFORMAT4:
1950 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1951 break;
1952 }
1953 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1954 elements[idx].usage_idx = idx2;
1955 idx++;
1956 }
1957
1958 /* Now compute offsets, and initialize the rest of the fields */
1959 for (idx = 0, offset = 0; idx < size; ++idx)
1960 {
1961 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1962 elements[idx].input_slot = 0;
1963 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1964 elements[idx].offset = offset;
1965 offset += format_desc->component_count * format_desc->component_size;
1966 }
1967
1968 *ppVertexElements = elements;
1969 return size;
1970}
1971
1972static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1973 WINED3DVERTEXELEMENT* elements = NULL;
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1975 unsigned int size;
1976 DWORD hr;
1977
1978 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1979 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1980
1981 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1982 HeapFree(GetProcessHeap(), 0, elements);
1983 if (hr != S_OK) return hr;
1984
1985 return WINED3D_OK;
1986}
1987
1988static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1989 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1990 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1991{
1992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1993 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1994 HRESULT hr = WINED3D_OK;
1995
1996 if (!pFunction) return WINED3DERR_INVALIDCALL;
1997
1998 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1999 if (!object)
2000 {
2001 ERR("Out of memory\n");
2002 *ppVertexShader = NULL;
2003 return WINED3DERR_OUTOFVIDEOMEMORY;
2004 }
2005
2006 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2007 object->parent = parent;
2008 shader_init(&object->baseShader, iface);
2009 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2010 *ppVertexShader = (IWineD3DVertexShader *)object;
2011
2012 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2013
2014 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2015 if (FAILED(hr))
2016 {
2017 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2018 IWineD3DVertexShader_Release(*ppVertexShader);
2019 *ppVertexShader = NULL;
2020 return hr;
2021 }
2022
2023 return hr;
2024}
2025
2026static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2027 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2028 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2029{
2030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2031 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2032 HRESULT hr = WINED3D_OK;
2033
2034 if (!pFunction) return WINED3DERR_INVALIDCALL;
2035
2036 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2037 if (!object)
2038 {
2039 ERR("Out of memory\n");
2040 *ppPixelShader = NULL;
2041 return WINED3DERR_OUTOFVIDEOMEMORY;
2042 }
2043
2044 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2045 object->parent = parent;
2046 shader_init(&object->baseShader, iface);
2047 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2048 *ppPixelShader = (IWineD3DPixelShader *)object;
2049
2050 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2051
2052 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2053 if (FAILED(hr))
2054 {
2055 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2056 IWineD3DPixelShader_Release(*ppPixelShader);
2057 *ppPixelShader = NULL;
2058 return hr;
2059 }
2060
2061 return hr;
2062}
2063
2064static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2065 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2066{
2067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2068 IWineD3DPaletteImpl *object;
2069 HRESULT hr;
2070 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2071
2072 /* Create the new object */
2073 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2074 if(!object) {
2075 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2076 return E_OUTOFMEMORY;
2077 }
2078
2079 object->lpVtbl = &IWineD3DPalette_Vtbl;
2080 object->ref = 1;
2081 object->Flags = Flags;
2082 object->parent = Parent;
2083 object->wineD3DDevice = This;
2084 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2085 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2086
2087 if(!object->hpal) {
2088 HeapFree( GetProcessHeap(), 0, object);
2089 return E_OUTOFMEMORY;
2090 }
2091
2092 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2093 if(FAILED(hr)) {
2094 IWineD3DPalette_Release((IWineD3DPalette *) object);
2095 return hr;
2096 }
2097
2098 *Palette = (IWineD3DPalette *) object;
2099
2100 return WINED3D_OK;
2101}
2102
2103static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2104 HBITMAP hbm;
2105 BITMAP bm;
2106 HRESULT hr;
2107 HDC dcb = NULL, dcs = NULL;
2108 WINEDDCOLORKEY colorkey;
2109
2110 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2111 if(hbm)
2112 {
2113 GetObjectA(hbm, sizeof(BITMAP), &bm);
2114 dcb = CreateCompatibleDC(NULL);
2115 if(!dcb) goto out;
2116 SelectObject(dcb, hbm);
2117 }
2118 else
2119 {
2120 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2121 * couldn't be loaded
2122 */
2123 memset(&bm, 0, sizeof(bm));
2124 bm.bmWidth = 32;
2125 bm.bmHeight = 32;
2126 }
2127
2128 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2129 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2130 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2131 if(FAILED(hr)) {
2132 ERR("Wine logo requested, but failed to create surface\n");
2133 goto out;
2134 }
2135
2136 if(dcb) {
2137 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2138 if(FAILED(hr)) goto out;
2139 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2140 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2141
2142 colorkey.dwColorSpaceLowValue = 0;
2143 colorkey.dwColorSpaceHighValue = 0;
2144 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2145 } else {
2146 /* Fill the surface with a white color to show that wined3d is there */
2147 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2148 }
2149
2150 out:
2151 if(dcb) {
2152 DeleteDC(dcb);
2153 }
2154 if(hbm) {
2155 DeleteObject(hbm);
2156 }
2157 return;
2158}
2159
2160static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2161 unsigned int i;
2162 /* Under DirectX you can have texture stage operations even if no texture is
2163 bound, whereas opengl will only do texture operations when a valid texture is
2164 bound. We emulate this by creating dummy textures and binding them to each
2165 texture stage, but disable all stages by default. Hence if a stage is enabled
2166 then the default texture will kick in until replaced by a SetTexture call */
2167 ENTER_GL();
2168
2169 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2170 /* The dummy texture does not have client storage backing */
2171 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2172 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2173 }
2174 for (i = 0; i < GL_LIMITS(textures); i++) {
2175 GLubyte white = 255;
2176
2177 /* Make appropriate texture active */
2178 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2179 checkGLcall("glActiveTextureARB");
2180
2181 /* Generate an opengl texture name */
2182 glGenTextures(1, &This->dummyTextureName[i]);
2183 checkGLcall("glGenTextures");
2184 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2185
2186 /* Generate a dummy 2d texture (not using 1d because they cause many
2187 * DRI drivers fall back to sw) */
2188 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2189 checkGLcall("glBindTexture");
2190
2191 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2192 checkGLcall("glTexImage2D");
2193 }
2194 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2195 /* Reenable because if supported it is enabled by default */
2196 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2197 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2198 }
2199
2200 LEAVE_GL();
2201}
2202
2203static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2204 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2205{
2206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2207 IWineD3DSwapChainImpl *swapchain = NULL;
2208 HRESULT hr;
2209 DWORD state;
2210 unsigned int i;
2211
2212 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2213
2214 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2215 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2216
2217 /* TODO: Test if OpenGL is compiled in and loaded */
2218
2219 TRACE("(%p) : Creating stateblock\n", This);
2220 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2221 hr = IWineD3DDevice_CreateStateBlock(iface,
2222 WINED3DSBT_INIT,
2223 (IWineD3DStateBlock **)&This->stateBlock,
2224 NULL);
2225 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2226 WARN("Failed to create stateblock\n");
2227 goto err_out;
2228 }
2229 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2230 This->updateStateBlock = This->stateBlock;
2231 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2232
2233 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2234 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2235
2236 This->NumberOfPalettes = 1;
2237 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2238 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2239 ERR("Out of memory!\n");
2240 goto err_out;
2241 }
2242 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2243 if(!This->palettes[0]) {
2244 ERR("Out of memory!\n");
2245 goto err_out;
2246 }
2247 for (i = 0; i < 256; ++i) {
2248 This->palettes[0][i].peRed = 0xFF;
2249 This->palettes[0][i].peGreen = 0xFF;
2250 This->palettes[0][i].peBlue = 0xFF;
2251 This->palettes[0][i].peFlags = 0xFF;
2252 }
2253 This->currentPalette = 0;
2254
2255 /* Initialize the texture unit mapping to a 1:1 mapping */
2256 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2257 if (state < GL_LIMITS(fragment_samplers)) {
2258 This->texUnitMap[state] = state;
2259 This->rev_tex_unit_map[state] = state;
2260 } else {
2261 This->texUnitMap[state] = -1;
2262 This->rev_tex_unit_map[state] = -1;
2263 }
2264 }
2265
2266 /* Setup the implicit swapchain */
2267 TRACE("Creating implicit swapchain\n");
2268 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2269 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2270 if (FAILED(hr))
2271 {
2272 WARN("Failed to create implicit swapchain\n");
2273 goto err_out;
2274 }
2275
2276 This->NumberOfSwapChains = 1;
2277 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2278 if(!This->swapchains) {
2279 ERR("Out of memory!\n");
2280 goto err_out;
2281 }
2282 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2283
2284 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2285 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2286 This->render_targets[0] = swapchain->backBuffer[0];
2287 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2288 }
2289 else {
2290 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2291 This->render_targets[0] = swapchain->frontBuffer;
2292 This->lastActiveRenderTarget = swapchain->frontBuffer;
2293 }
2294 IWineD3DSurface_AddRef(This->render_targets[0]);
2295 This->activeContext = swapchain->context[0];
2296 This->lastThread = GetCurrentThreadId();
2297
2298 /* Depth Stencil support */
2299 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2300 if (NULL != This->stencilBufferTarget) {
2301 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2302 }
2303
2304 hr = This->shader_backend->shader_alloc_private(iface);
2305 if(FAILED(hr)) {
2306 TRACE("Shader private data couldn't be allocated\n");
2307 goto err_out;
2308 }
2309 hr = This->frag_pipe->alloc_private(iface);
2310 if(FAILED(hr)) {
2311 TRACE("Fragment pipeline private data couldn't be allocated\n");
2312 goto err_out;
2313 }
2314 hr = This->blitter->alloc_private(iface);
2315 if(FAILED(hr)) {
2316 TRACE("Blitter private data couldn't be allocated\n");
2317 goto err_out;
2318 }
2319
2320 /* Set up some starting GL setup */
2321
2322 /* Setup all the devices defaults */
2323 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2324 create_dummy_textures(This);
2325
2326 ENTER_GL();
2327
2328 /* Initialize the current view state */
2329 This->view_ident = 1;
2330 This->contexts[0]->last_was_rhw = 0;
2331 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2332 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2333
2334 switch(wined3d_settings.offscreen_rendering_mode) {
2335 case ORM_FBO:
2336 case ORM_PBUFFER:
2337 This->offscreenBuffer = GL_BACK;
2338 break;
2339
2340 case ORM_BACKBUFFER:
2341 {
2342 if(This->activeContext->aux_buffers > 0) {
2343 TRACE("Using auxilliary buffer for offscreen rendering\n");
2344 This->offscreenBuffer = GL_AUX0;
2345 } else {
2346 TRACE("Using back buffer for offscreen rendering\n");
2347 This->offscreenBuffer = GL_BACK;
2348 }
2349 }
2350 }
2351
2352 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2353 LEAVE_GL();
2354
2355 /* Clear the screen */
2356 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2357 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2358 0x00, 1.0, 0);
2359
2360 This->d3d_initialized = TRUE;
2361
2362 if(wined3d_settings.logo) {
2363 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2364 }
2365 This->highest_dirty_ps_const = 0;
2366 This->highest_dirty_vs_const = 0;
2367 return WINED3D_OK;
2368
2369err_out:
2370 HeapFree(GetProcessHeap(), 0, This->render_targets);
2371 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2372 HeapFree(GetProcessHeap(), 0, This->swapchains);
2373 This->NumberOfSwapChains = 0;
2374 if(This->palettes) {
2375 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2376 HeapFree(GetProcessHeap(), 0, This->palettes);
2377 }
2378 This->NumberOfPalettes = 0;
2379 if(swapchain) {
2380 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2381 }
2382 if(This->stateBlock) {
2383 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2384 This->stateBlock = NULL;
2385 }
2386 if (This->blit_priv) {
2387 This->blitter->free_private(iface);
2388 }
2389 if (This->fragment_priv) {
2390 This->frag_pipe->free_private(iface);
2391 }
2392 if (This->shader_priv) {
2393 This->shader_backend->shader_free_private(iface);
2394 }
2395 return hr;
2396}
2397
2398static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2399 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2400{
2401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2402 IWineD3DSwapChainImpl *swapchain = NULL;
2403 HRESULT hr;
2404
2405 /* Setup the implicit swapchain */
2406 TRACE("Creating implicit swapchain\n");
2407 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2408 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2409 if (FAILED(hr))
2410 {
2411 WARN("Failed to create implicit swapchain\n");
2412 goto err_out;
2413 }
2414
2415 This->NumberOfSwapChains = 1;
2416 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2417 if(!This->swapchains) {
2418 ERR("Out of memory!\n");
2419 goto err_out;
2420 }
2421 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2422 return WINED3D_OK;
2423
2424err_out:
2425 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2426 return hr;
2427}
2428
2429static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2430{
2431 IWineD3DResource_UnLoad(resource);
2432 IWineD3DResource_Release(resource);
2433 return WINED3D_OK;
2434}
2435
2436static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2438 int sampler;
2439 UINT i;
2440 TRACE("(%p)\n", This);
2441
2442 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2443
2444 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2445 * it was created. Thus make sure a context is active for the glDelete* calls
2446 */
2447 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2448
2449 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2450
2451 /* Unload resources */
2452 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2453
2454 TRACE("Deleting high order patches\n");
2455 for(i = 0; i < PATCHMAP_SIZE; i++) {
2456 struct list *e1, *e2;
2457 struct WineD3DRectPatch *patch;
2458 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2459 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2460 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2461 }
2462 }
2463
2464 /* Delete the palette conversion shader if it is around */
2465 if(This->paletteConversionShader) {
2466 ENTER_GL();
2467 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2468 LEAVE_GL();
2469 This->paletteConversionShader = 0;
2470 }
2471
2472 /* Delete the pbuffer context if there is any */
2473 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2474
2475 /* Delete the mouse cursor texture */
2476 if(This->cursorTexture) {
2477 ENTER_GL();
2478 glDeleteTextures(1, &This->cursorTexture);
2479 LEAVE_GL();
2480 This->cursorTexture = 0;
2481 }
2482
2483 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2484 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2485 }
2486 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2487 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2488 }
2489
2490 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2491 * private data, it might contain opengl pointers
2492 */
2493 if(This->depth_blt_texture) {
2494 ENTER_GL();
2495 glDeleteTextures(1, &This->depth_blt_texture);
2496 LEAVE_GL();
2497 This->depth_blt_texture = 0;
2498 }
2499 if (This->depth_blt_rb) {
2500 ENTER_GL();
2501 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2502 LEAVE_GL();
2503 This->depth_blt_rb = 0;
2504 This->depth_blt_rb_w = 0;
2505 This->depth_blt_rb_h = 0;
2506 }
2507
2508 /* Release the update stateblock */
2509 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2510 if(This->updateStateBlock != This->stateBlock)
2511 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2512 }
2513 This->updateStateBlock = NULL;
2514
2515 { /* because were not doing proper internal refcounts releasing the primary state block
2516 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2517 to set this->stateBlock = NULL; first */
2518 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2519 This->stateBlock = NULL;
2520
2521 /* Release the stateblock */
2522 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2523 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2524 }
2525 }
2526
2527 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2528 This->blitter->free_private(iface);
2529 This->frag_pipe->free_private(iface);
2530 This->shader_backend->shader_free_private(iface);
2531
2532 /* Release the buffers (with sanity checks)*/
2533 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2534 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2535 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2536 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2537 }
2538 This->stencilBufferTarget = NULL;
2539
2540 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2541 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2542 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2543 }
2544 TRACE("Setting rendertarget to NULL\n");
2545 This->render_targets[0] = NULL;
2546
2547 if (This->auto_depth_stencil_buffer) {
2548 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2549 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2550 }
2551 This->auto_depth_stencil_buffer = NULL;
2552 }
2553
2554 for(i=0; i < This->NumberOfSwapChains; i++) {
2555 TRACE("Releasing the implicit swapchain %d\n", i);
2556 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2557 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2558 }
2559 }
2560
2561 HeapFree(GetProcessHeap(), 0, This->swapchains);
2562 This->swapchains = NULL;
2563 This->NumberOfSwapChains = 0;
2564
2565 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2566 HeapFree(GetProcessHeap(), 0, This->palettes);
2567 This->palettes = NULL;
2568 This->NumberOfPalettes = 0;
2569
2570 HeapFree(GetProcessHeap(), 0, This->render_targets);
2571 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2572 This->render_targets = NULL;
2573 This->draw_buffers = NULL;
2574
2575 This->d3d_initialized = FALSE;
2576 return WINED3D_OK;
2577}
2578
2579static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2581 unsigned int i;
2582
2583 for(i=0; i < This->NumberOfSwapChains; i++) {
2584 TRACE("Releasing the implicit swapchain %d\n", i);
2585 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2586 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2587 }
2588 }
2589
2590 HeapFree(GetProcessHeap(), 0, This->swapchains);
2591 This->swapchains = NULL;
2592 This->NumberOfSwapChains = 0;
2593 return WINED3D_OK;
2594}
2595
2596/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2597 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2598 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2599 *
2600 * There is no way to deactivate thread safety once it is enabled.
2601 */
2602static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2604
2605 /*For now just store the flag(needed in case of ddraw) */
2606 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2607
2608 return;
2609}
2610
2611static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2612 const WINED3DDISPLAYMODE* pMode) {
2613 DEVMODEW devmode;
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 LONG ret;
2616 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2617 RECT clip_rc;
2618
2619 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2620
2621 /* Resize the screen even without a window:
2622 * The app could have unset it with SetCooperativeLevel, but not called
2623 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2624 * but we don't have any hwnd
2625 */
2626
2627 memset(&devmode, 0, sizeof(devmode));
2628 devmode.dmSize = sizeof(devmode);
2629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2630 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2631 devmode.dmPelsWidth = pMode->Width;
2632 devmode.dmPelsHeight = pMode->Height;
2633
2634 devmode.dmDisplayFrequency = pMode->RefreshRate;
2635 if (pMode->RefreshRate != 0) {
2636 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2637 }
2638
2639 /* Only change the mode if necessary */
2640 if( (This->ddraw_width == pMode->Width) &&
2641 (This->ddraw_height == pMode->Height) &&
2642 (This->ddraw_format == pMode->Format) &&
2643 (pMode->RefreshRate == 0) ) {
2644 return WINED3D_OK;
2645 }
2646
2647 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2648 if (ret != DISP_CHANGE_SUCCESSFUL) {
2649 if(devmode.dmDisplayFrequency != 0) {
2650 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2651 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2652 devmode.dmDisplayFrequency = 0;
2653 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2654 }
2655 if(ret != DISP_CHANGE_SUCCESSFUL) {
2656 return WINED3DERR_NOTAVAILABLE;
2657 }
2658 }
2659
2660 /* Store the new values */
2661 This->ddraw_width = pMode->Width;
2662 This->ddraw_height = pMode->Height;
2663 This->ddraw_format = pMode->Format;
2664
2665 /* And finally clip mouse to our screen */
2666 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2667 ClipCursor(&clip_rc);
2668
2669 return WINED3D_OK;
2670}
2671
2672static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2674 *ppD3D= This->wineD3D;
2675 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2676 IWineD3D_AddRef(*ppD3D);
2677 return WINED3D_OK;
2678}
2679
2680static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2682
2683 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2684 (This->adapter->TextureRam/(1024*1024)),
2685 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2686 /* return simulated texture memory left */
2687 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2688}
2689
2690/*****
2691 * Get / Set Stream Source
2692 *****/
2693static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2694 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2695{
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 IWineD3DBuffer *oldSrc;
2698
2699 if (StreamNumber >= MAX_STREAMS) {
2700 WARN("Stream out of range %d\n", StreamNumber);
2701 return WINED3DERR_INVALIDCALL;
2702 } else if(OffsetInBytes & 0x3) {
2703 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2704 return WINED3DERR_INVALIDCALL;
2705 }
2706
2707 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2708 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2709
2710 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2711
2712 if(oldSrc == pStreamData &&
2713 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2714 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2715 TRACE("Application is setting the old values over, nothing to do\n");
2716 return WINED3D_OK;
2717 }
2718
2719 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2720 if (pStreamData) {
2721 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2722 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2723 }
2724
2725 /* Handle recording of state blocks */
2726 if (This->isRecordingState) {
2727 TRACE("Recording... not performing anything\n");
2728 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2729 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2730 return WINED3D_OK;
2731 }
2732
2733 if (pStreamData != NULL) {
2734 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2735 IWineD3DBuffer_AddRef(pStreamData);
2736 }
2737 if (oldSrc != NULL) {
2738 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2739 IWineD3DBuffer_Release(oldSrc);
2740 }
2741
2742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2743
2744 return WINED3D_OK;
2745}
2746
2747static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2748 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2749{
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751
2752 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2753 This->stateBlock->streamSource[StreamNumber],
2754 This->stateBlock->streamOffset[StreamNumber],
2755 This->stateBlock->streamStride[StreamNumber]);
2756
2757 if (StreamNumber >= MAX_STREAMS) {
2758 WARN("Stream out of range %d\n", StreamNumber);
2759 return WINED3DERR_INVALIDCALL;
2760 }
2761 *pStream = This->stateBlock->streamSource[StreamNumber];
2762 *pStride = This->stateBlock->streamStride[StreamNumber];
2763 if (pOffset) {
2764 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2765 }
2766
2767 if (*pStream != NULL) {
2768 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2769 }
2770 return WINED3D_OK;
2771}
2772
2773static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2776 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2777
2778 /* Verify input at least in d3d9 this is invalid*/
2779 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2780 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2781 return WINED3DERR_INVALIDCALL;
2782 }
2783 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2784 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2785 return WINED3DERR_INVALIDCALL;
2786 }
2787 if( Divider == 0 ){
2788 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2789 return WINED3DERR_INVALIDCALL;
2790 }
2791
2792 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2793 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2794
2795 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2796 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2797
2798 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2799 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2801 }
2802
2803 return WINED3D_OK;
2804}
2805
2806static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808
2809 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2810 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2811
2812 TRACE("(%p) : returning %d\n", This, *Divider);
2813
2814 return WINED3D_OK;
2815}
2816
2817/*****
2818 * Get / Set & Multiply Transform
2819 *****/
2820static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2822
2823 /* Most of this routine, comments included copied from ddraw tree initially: */
2824 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2825
2826 /* Handle recording of state blocks */
2827 if (This->isRecordingState) {
2828 TRACE("Recording... not performing anything\n");
2829 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2830 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2831 return WINED3D_OK;
2832 }
2833
2834 /*
2835 * If the new matrix is the same as the current one,
2836 * we cut off any further processing. this seems to be a reasonable
2837 * optimization because as was noticed, some apps (warcraft3 for example)
2838 * tend towards setting the same matrix repeatedly for some reason.
2839 *
2840 * From here on we assume that the new matrix is different, wherever it matters.
2841 */
2842 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2843 TRACE("The app is setting the same matrix over again\n");
2844 return WINED3D_OK;
2845 } else {
2846 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2847 }
2848
2849 /*
2850 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2851 where ViewMat = Camera space, WorldMat = world space.
2852
2853 In OpenGL, camera and world space is combined into GL_MODELVIEW
2854 matrix. The Projection matrix stay projection matrix.
2855 */
2856
2857 /* Capture the times we can just ignore the change for now */
2858 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2859 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2860 /* Handled by the state manager */
2861 }
2862
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2864 return WINED3D_OK;
2865
2866}
2867static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2870 *pMatrix = This->stateBlock->transforms[State];
2871 return WINED3D_OK;
2872}
2873
2874static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2875 const WINED3DMATRIX *mat = NULL;
2876 WINED3DMATRIX temp;
2877
2878 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2879 * below means it will be recorded in a state block change, but it
2880 * works regardless where it is recorded.
2881 * If this is found to be wrong, change to StateBlock.
2882 */
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2885
2886 if (State <= HIGHEST_TRANSFORMSTATE)
2887 {
2888 mat = &This->updateStateBlock->transforms[State];
2889 } else {
2890 FIXME("Unhandled transform state!!\n");
2891 }
2892
2893 multiply_matrix(&temp, mat, pMatrix);
2894
2895 /* Apply change via set transform - will reapply to eg. lights this way */
2896 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2897}
2898
2899/*****
2900 * Get / Set Light
2901 *****/
2902/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2903 you can reference any indexes you want as long as that number max are enabled at any
2904 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2905 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2906 but when recording, just build a chain pretty much of commands to be replayed. */
2907
2908static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2909 float rho;
2910 PLIGHTINFOEL *object = NULL;
2911 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2912 struct list *e;
2913
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2916
2917 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2918 * the gl driver.
2919 */
2920 if(!pLight) {
2921 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2922 return WINED3DERR_INVALIDCALL;
2923 }
2924
2925 switch(pLight->Type) {
2926 case WINED3DLIGHT_POINT:
2927 case WINED3DLIGHT_SPOT:
2928 case WINED3DLIGHT_PARALLELPOINT:
2929 case WINED3DLIGHT_GLSPOT:
2930 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2931 * most wanted
2932 */
2933 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2934 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2935 return WINED3DERR_INVALIDCALL;
2936 }
2937 break;
2938
2939 case WINED3DLIGHT_DIRECTIONAL:
2940 /* Ignores attenuation */
2941 break;
2942
2943 default:
2944 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2945 return WINED3DERR_INVALIDCALL;
2946 }
2947
2948 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2949 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2950 if(object->OriginalIndex == Index) break;
2951 object = NULL;
2952 }
2953
2954 if(!object) {
2955 TRACE("Adding new light\n");
2956 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2957 if(!object) {
2958 ERR("Out of memory error when allocating a light\n");
2959 return E_OUTOFMEMORY;
2960 }
2961 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2962 object->glIndex = -1;
2963 object->OriginalIndex = Index;
2964 object->changed = TRUE;
2965 }
2966
2967 /* Initialize the object */
2968 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,
2969 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2970 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2971 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2972 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2973 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2974 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2975
2976 /* Save away the information */
2977 object->OriginalParms = *pLight;
2978
2979 switch (pLight->Type) {
2980 case WINED3DLIGHT_POINT:
2981 /* Position */
2982 object->lightPosn[0] = pLight->Position.x;
2983 object->lightPosn[1] = pLight->Position.y;
2984 object->lightPosn[2] = pLight->Position.z;
2985 object->lightPosn[3] = 1.0f;
2986 object->cutoff = 180.0f;
2987 /* FIXME: Range */
2988 break;
2989
2990 case WINED3DLIGHT_DIRECTIONAL:
2991 /* Direction */
2992 object->lightPosn[0] = -pLight->Direction.x;
2993 object->lightPosn[1] = -pLight->Direction.y;
2994 object->lightPosn[2] = -pLight->Direction.z;
2995 object->lightPosn[3] = 0.0;
2996 object->exponent = 0.0f;
2997 object->cutoff = 180.0f;
2998 break;
2999
3000 case WINED3DLIGHT_SPOT:
3001 /* Position */
3002 object->lightPosn[0] = pLight->Position.x;
3003 object->lightPosn[1] = pLight->Position.y;
3004 object->lightPosn[2] = pLight->Position.z;
3005 object->lightPosn[3] = 1.0;
3006
3007 /* Direction */
3008 object->lightDirn[0] = pLight->Direction.x;
3009 object->lightDirn[1] = pLight->Direction.y;
3010 object->lightDirn[2] = pLight->Direction.z;
3011 object->lightDirn[3] = 1.0;
3012
3013 /*
3014 * opengl-ish and d3d-ish spot lights use too different models for the
3015 * light "intensity" as a function of the angle towards the main light direction,
3016 * so we only can approximate very roughly.
3017 * however spot lights are rather rarely used in games (if ever used at all).
3018 * furthermore if still used, probably nobody pays attention to such details.
3019 */
3020 if (pLight->Falloff == 0) {
3021 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3022 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3023 * will always be 1.0 for both of them, and we don't have to care for the
3024 * rest of the rather complex calculation
3025 */
3026 object->exponent = 0;
3027 } else {
3028 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3029 if (rho < 0.0001) rho = 0.0001f;
3030 object->exponent = -0.3/log(cos(rho/2));
3031 }
3032 if (object->exponent > 128.0) {
3033 object->exponent = 128.0;
3034 }
3035 object->cutoff = pLight->Phi*90/M_PI;
3036
3037 /* FIXME: Range */
3038 break;
3039
3040 default:
3041 FIXME("Unrecognized light type %d\n", pLight->Type);
3042 }
3043
3044 /* Update the live definitions if the light is currently assigned a glIndex */
3045 if (object->glIndex != -1 && !This->isRecordingState) {
3046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3047 }
3048 return WINED3D_OK;
3049}
3050
3051static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3052 PLIGHTINFOEL *lightInfo = NULL;
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3055 struct list *e;
3056 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3057
3058 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3059 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3060 if(lightInfo->OriginalIndex == Index) break;
3061 lightInfo = NULL;
3062 }
3063
3064 if (lightInfo == NULL) {
3065 TRACE("Light information requested but light not defined\n");
3066 return WINED3DERR_INVALIDCALL;
3067 }
3068
3069 *pLight = lightInfo->OriginalParms;
3070 return WINED3D_OK;
3071}
3072
3073/*****
3074 * Get / Set Light Enable
3075 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3076 *****/
3077static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3078 PLIGHTINFOEL *lightInfo = NULL;
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3081 struct list *e;
3082 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3083
3084 /* Tests show true = 128...not clear why */
3085 Enable = Enable? 128: 0;
3086
3087 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3088 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3089 if(lightInfo->OriginalIndex == Index) break;
3090 lightInfo = NULL;
3091 }
3092 TRACE("Found light: %p\n", lightInfo);
3093
3094 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3095 if (lightInfo == NULL) {
3096
3097 TRACE("Light enabled requested but light not defined, so defining one!\n");
3098 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3099
3100 /* Search for it again! Should be fairly quick as near head of list */
3101 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3102 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3103 if(lightInfo->OriginalIndex == Index) break;
3104 lightInfo = NULL;
3105 }
3106 if (lightInfo == NULL) {
3107 FIXME("Adding default lights has failed dismally\n");
3108 return WINED3DERR_INVALIDCALL;
3109 }
3110 }
3111
3112 lightInfo->enabledChanged = TRUE;
3113 if(!Enable) {
3114 if(lightInfo->glIndex != -1) {
3115 if(!This->isRecordingState) {
3116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3117 }
3118
3119 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3120 lightInfo->glIndex = -1;
3121 } else {
3122 TRACE("Light already disabled, nothing to do\n");
3123 }
3124 lightInfo->enabled = FALSE;
3125 } else {
3126 lightInfo->enabled = TRUE;
3127 if (lightInfo->glIndex != -1) {
3128 /* nop */
3129 TRACE("Nothing to do as light was enabled\n");
3130 } else {
3131 int i;
3132 /* Find a free gl light */
3133 for(i = 0; i < This->maxConcurrentLights; i++) {
3134 if(This->updateStateBlock->activeLights[i] == NULL) {
3135 This->updateStateBlock->activeLights[i] = lightInfo;
3136 lightInfo->glIndex = i;
3137 break;
3138 }
3139 }
3140 if(lightInfo->glIndex == -1) {
3141 /* Our tests show that Windows returns D3D_OK in this situation, even with
3142 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3143 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3144 * as well for those lights.
3145 *
3146 * TODO: Test how this affects rendering
3147 */
3148 WARN("Too many concurrently active lights\n");
3149 return WINED3D_OK;
3150 }
3151
3152 /* i == lightInfo->glIndex */
3153 if(!This->isRecordingState) {
3154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3155 }
3156 }
3157 }
3158
3159 return WINED3D_OK;
3160}
3161
3162static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3163
3164 PLIGHTINFOEL *lightInfo = NULL;
3165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 struct list *e;
3167 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3168 TRACE("(%p) : for idx(%d)\n", This, Index);
3169
3170 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3171 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3172 if(lightInfo->OriginalIndex == Index) break;
3173 lightInfo = NULL;
3174 }
3175
3176 if (lightInfo == NULL) {
3177 TRACE("Light enabled state requested but light not defined\n");
3178 return WINED3DERR_INVALIDCALL;
3179 }
3180 /* true is 128 according to SetLightEnable */
3181 *pEnable = lightInfo->enabled ? 128 : 0;
3182 return WINED3D_OK;
3183}
3184
3185/*****
3186 * Get / Set Clip Planes
3187 *****/
3188static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3191
3192 /* Validate Index */
3193 if (Index >= GL_LIMITS(clipplanes)) {
3194 TRACE("Application has requested clipplane this device doesn't support\n");
3195 return WINED3DERR_INVALIDCALL;
3196 }
3197
3198 This->updateStateBlock->changed.clipplane |= 1 << Index;
3199
3200 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3201 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3202 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3203 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3204 TRACE("Application is setting old values over, nothing to do\n");
3205 return WINED3D_OK;
3206 }
3207
3208 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3209 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3210 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3211 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3212
3213 /* Handle recording of state blocks */
3214 if (This->isRecordingState) {
3215 TRACE("Recording... not performing anything\n");
3216 return WINED3D_OK;
3217 }
3218
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3220
3221 return WINED3D_OK;
3222}
3223
3224static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 TRACE("(%p) : for idx %d\n", This, Index);
3227
3228 /* Validate Index */
3229 if (Index >= GL_LIMITS(clipplanes)) {
3230 TRACE("Application has requested clipplane this device doesn't support\n");
3231 return WINED3DERR_INVALIDCALL;
3232 }
3233
3234 pPlane[0] = This->stateBlock->clipplane[Index][0];
3235 pPlane[1] = This->stateBlock->clipplane[Index][1];
3236 pPlane[2] = This->stateBlock->clipplane[Index][2];
3237 pPlane[3] = This->stateBlock->clipplane[Index][3];
3238 return WINED3D_OK;
3239}
3240
3241/*****
3242 * Get / Set Clip Plane Status
3243 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3244 *****/
3245static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 FIXME("(%p) : stub\n", This);
3248 if (NULL == pClipStatus) {
3249 return WINED3DERR_INVALIDCALL;
3250 }
3251 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3252 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3253 return WINED3D_OK;
3254}
3255
3256static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 FIXME("(%p) : stub\n", This);
3259 if (NULL == pClipStatus) {
3260 return WINED3DERR_INVALIDCALL;
3261 }
3262 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3263 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3264 return WINED3D_OK;
3265}
3266
3267/*****
3268 * Get / Set Material
3269 *****/
3270static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272
3273 This->updateStateBlock->changed.material = TRUE;
3274 This->updateStateBlock->material = *pMaterial;
3275
3276 /* Handle recording of state blocks */
3277 if (This->isRecordingState) {
3278 TRACE("Recording... not performing anything\n");
3279 return WINED3D_OK;
3280 }
3281
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3283 return WINED3D_OK;
3284}
3285
3286static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3288 *pMaterial = This->updateStateBlock->material;
3289 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3290 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3291 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3292 pMaterial->Ambient.b, pMaterial->Ambient.a);
3293 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3294 pMaterial->Specular.b, pMaterial->Specular.a);
3295 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3296 pMaterial->Emissive.b, pMaterial->Emissive.a);
3297 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3298
3299 return WINED3D_OK;
3300}
3301
3302/*****
3303 * Get / Set Indices
3304 *****/
3305static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 IWineD3DBuffer *oldIdxs;
3308
3309 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3310 oldIdxs = This->updateStateBlock->pIndexData;
3311
3312 This->updateStateBlock->changed.indices = TRUE;
3313 This->updateStateBlock->pIndexData = pIndexData;
3314 This->updateStateBlock->IndexFmt = fmt;
3315
3316 /* Handle recording of state blocks */
3317 if (This->isRecordingState) {
3318 TRACE("Recording... not performing anything\n");
3319 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3320 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3321 return WINED3D_OK;
3322 }
3323
3324 if(oldIdxs != pIndexData) {
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3326 if(pIndexData) {
3327 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3328 IWineD3DBuffer_AddRef(pIndexData);
3329 }
3330 if(oldIdxs) {
3331 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3332 IWineD3DBuffer_Release(oldIdxs);
3333 }
3334 }
3335
3336 return WINED3D_OK;
3337}
3338
3339static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341
3342 *ppIndexData = This->stateBlock->pIndexData;
3343
3344 /* up ref count on ppindexdata */
3345 if (*ppIndexData) {
3346 IWineD3DBuffer_AddRef(*ppIndexData);
3347 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3348 }else{
3349 TRACE("(%p) No index data set\n", This);
3350 }
3351 TRACE("Returning %p\n", *ppIndexData);
3352
3353 return WINED3D_OK;
3354}
3355
3356/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3357static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 TRACE("(%p)->(%d)\n", This, BaseIndex);
3360
3361 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3362 TRACE("Application is setting the old value over, nothing to do\n");
3363 return WINED3D_OK;
3364 }
3365
3366 This->updateStateBlock->baseVertexIndex = BaseIndex;
3367
3368 if (This->isRecordingState) {
3369 TRACE("Recording... not performing anything\n");
3370 return WINED3D_OK;
3371 }
3372 /* The base vertex index affects the stream sources */
3373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3374 return WINED3D_OK;
3375}
3376
3377static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 TRACE("(%p) : base_index %p\n", This, base_index);
3380
3381 *base_index = This->stateBlock->baseVertexIndex;
3382
3383 TRACE("Returning %u\n", *base_index);
3384
3385 return WINED3D_OK;
3386}
3387
3388/*****
3389 * Get / Set Viewports
3390 *****/
3391static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3393
3394 TRACE("(%p)\n", This);
3395 This->updateStateBlock->changed.viewport = TRUE;
3396 This->updateStateBlock->viewport = *pViewport;
3397
3398 /* Handle recording of state blocks */
3399 if (This->isRecordingState) {
3400 TRACE("Recording... not performing anything\n");
3401 return WINED3D_OK;
3402 }
3403
3404 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3405 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3406
3407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3408 return WINED3D_OK;
3409
3410}
3411
3412static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 TRACE("(%p)\n", This);
3415 *pViewport = This->stateBlock->viewport;
3416 return WINED3D_OK;
3417}
3418
3419/*****
3420 * Get / Set Render States
3421 * TODO: Verify against dx9 definitions
3422 *****/
3423static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3424
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 DWORD oldValue = This->stateBlock->renderState[State];
3427
3428 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3429
3430 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3431 This->updateStateBlock->renderState[State] = Value;
3432
3433 /* Handle recording of state blocks */
3434 if (This->isRecordingState) {
3435 TRACE("Recording... not performing anything\n");
3436 return WINED3D_OK;
3437 }
3438
3439 /* Compared here and not before the assignment to allow proper stateblock recording */
3440 if(Value == oldValue) {
3441 TRACE("Application is setting the old value over, nothing to do\n");
3442 } else {
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3444 }
3445
3446 return WINED3D_OK;
3447}
3448
3449static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3452 *pValue = This->stateBlock->renderState[State];
3453 return WINED3D_OK;
3454}
3455
3456/*****
3457 * Get / Set Sampler States
3458 * TODO: Verify against dx9 definitions
3459 *****/
3460
3461static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 DWORD oldValue;
3464
3465 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3466 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3467
3468 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3469 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3470 }
3471
3472 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3473 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3474 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3475 }
3476 /**
3477 * SetSampler is designed to allow for more than the standard up to 8 textures
3478 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3479 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3480 *
3481 * http://developer.nvidia.com/object/General_FAQ.html#t6
3482 *
3483 * There are two new settings for GForce
3484 * the sampler one:
3485 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3486 * and the texture one:
3487 * GL_MAX_TEXTURE_COORDS_ARB.
3488 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3489 ******************/
3490
3491 oldValue = This->stateBlock->samplerState[Sampler][Type];
3492 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3493 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3494
3495 /* Handle recording of state blocks */
3496 if (This->isRecordingState) {
3497 TRACE("Recording... not performing anything\n");
3498 return WINED3D_OK;
3499 }
3500
3501 if(oldValue == Value) {
3502 TRACE("Application is setting the old value over, nothing to do\n");
3503 return WINED3D_OK;
3504 }
3505
3506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3507
3508 return WINED3D_OK;
3509}
3510
3511static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3513
3514 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3515 This, Sampler, debug_d3dsamplerstate(Type), Type);
3516
3517 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3518 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3519 }
3520
3521 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3522 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3523 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3524 }
3525 *Value = This->stateBlock->samplerState[Sampler][Type];
3526 TRACE("(%p) : Returning %#x\n", This, *Value);
3527
3528 return WINED3D_OK;
3529}
3530
3531static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533
3534 This->updateStateBlock->changed.scissorRect = TRUE;
3535 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3536 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3537 return WINED3D_OK;
3538 }
3539 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3540
3541 if(This->isRecordingState) {
3542 TRACE("Recording... not performing anything\n");
3543 return WINED3D_OK;
3544 }
3545
3546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3547
3548 return WINED3D_OK;
3549}
3550
3551static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3553
3554 *pRect = This->updateStateBlock->scissorRect;
3555 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3556 return WINED3D_OK;
3557}
3558
3559static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3561 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3562
3563 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3564
3565 This->updateStateBlock->vertexDecl = pDecl;
3566 This->updateStateBlock->changed.vertexDecl = TRUE;
3567
3568 if (This->isRecordingState) {
3569 TRACE("Recording... not performing anything\n");
3570 return WINED3D_OK;
3571 } else if(pDecl == oldDecl) {
3572 /* Checked after the assignment to allow proper stateblock recording */
3573 TRACE("Application is setting the old declaration over, nothing to do\n");
3574 return WINED3D_OK;
3575 }
3576
3577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3578 return WINED3D_OK;
3579}
3580
3581static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583
3584 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3585
3586 *ppDecl = This->stateBlock->vertexDecl;
3587 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3588 return WINED3D_OK;
3589}
3590
3591static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3593 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3594
3595 This->updateStateBlock->vertexShader = pShader;
3596 This->updateStateBlock->changed.vertexShader = TRUE;
3597
3598 if (This->isRecordingState) {
3599 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3600 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3601 TRACE("Recording... not performing anything\n");
3602 return WINED3D_OK;
3603 } else if(oldShader == pShader) {
3604 /* Checked here to allow proper stateblock recording */
3605 TRACE("App is setting the old shader over, nothing to do\n");
3606 return WINED3D_OK;
3607 }
3608
3609 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3610 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3611 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3612
3613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3614
3615 return WINED3D_OK;
3616}
3617
3618static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3620
3621 if (NULL == ppShader) {
3622 return WINED3DERR_INVALIDCALL;
3623 }
3624 *ppShader = This->stateBlock->vertexShader;
3625 if( NULL != *ppShader)
3626 IWineD3DVertexShader_AddRef(*ppShader);
3627
3628 TRACE("(%p) : returning %p\n", This, *ppShader);
3629 return WINED3D_OK;
3630}
3631
3632static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3633 IWineD3DDevice *iface,
3634 UINT start,
3635 CONST BOOL *srcData,
3636 UINT count) {
3637
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3639 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3640
3641 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3642 iface, srcData, start, count);
3643
3644 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3645
3646 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3647 for (i = 0; i < cnt; i++)
3648 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3649
3650 for (i = start; i < cnt + start; ++i) {
3651 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3652 }
3653
3654 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3655
3656 return WINED3D_OK;
3657}
3658
3659static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3660 IWineD3DDevice *iface,
3661 UINT start,
3662 BOOL *dstData,
3663 UINT count) {
3664
3665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3666 int cnt = min(count, MAX_CONST_B - start);
3667
3668 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3669 iface, dstData, start, count);
3670
3671 if (dstData == NULL || cnt < 0)
3672 return WINED3DERR_INVALIDCALL;
3673
3674 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3675 return WINED3D_OK;
3676}
3677
3678static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3679 IWineD3DDevice *iface,
3680 UINT start,
3681 CONST int *srcData,
3682 UINT count) {
3683
3684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3685 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3686
3687 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3688 iface, srcData, start, count);
3689
3690 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3691
3692 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3693 for (i = 0; i < cnt; i++)
3694 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3695 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3696
3697 for (i = start; i < cnt + start; ++i) {
3698 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3699 }
3700
3701 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3702
3703 return WINED3D_OK;
3704}
3705
3706static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3707 IWineD3DDevice *iface,
3708 UINT start,
3709 int *dstData,
3710 UINT count) {
3711
3712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3713 int cnt = min(count, MAX_CONST_I - start);
3714
3715 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3716 iface, dstData, start, count);
3717
3718 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3719 return WINED3DERR_INVALIDCALL;
3720
3721 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3722 return WINED3D_OK;
3723}
3724
3725static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3726 IWineD3DDevice *iface,
3727 UINT start,
3728 CONST float *srcData,
3729 UINT count) {
3730
3731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3732 UINT i;
3733
3734 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3735 iface, srcData, start, count);
3736
3737 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3738 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3739 return WINED3DERR_INVALIDCALL;
3740
3741 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3742 if(TRACE_ON(d3d)) {
3743 for (i = 0; i < count; i++)
3744 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3745 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3746 }
3747
3748 if (!This->isRecordingState)
3749 {
3750 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3752 }
3753
3754 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3755 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3756
3757 return WINED3D_OK;
3758}
3759
3760static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3761 IWineD3DDevice *iface,
3762 UINT start,
3763 float *dstData,
3764 UINT count) {
3765
3766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3767 int cnt = min(count, This->d3d_vshader_constantF - start);
3768
3769 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3770 iface, dstData, start, count);
3771
3772 if (dstData == NULL || cnt < 0)
3773 return WINED3DERR_INVALIDCALL;
3774
3775 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3776 return WINED3D_OK;
3777}
3778
3779static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3780 DWORD i;
3781 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3782 {
3783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3784 }
3785}
3786
3787static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3788 int i = This->rev_tex_unit_map[unit];
3789 int j = This->texUnitMap[stage];
3790
3791 This->texUnitMap[stage] = unit;
3792 if (i != -1 && i != stage) {
3793 This->texUnitMap[i] = -1;
3794 }
3795
3796 This->rev_tex_unit_map[unit] = stage;
3797 if (j != -1 && j != unit) {
3798 This->rev_tex_unit_map[j] = -1;
3799 }
3800}
3801
3802static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3803 int i;
3804
3805 This->fixed_function_usage_map = 0;
3806 for (i = 0; i < MAX_TEXTURES; ++i) {
3807 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3808 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3809 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3810 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3811 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3812 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3813 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3814 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3815
3816 if (color_op == WINED3DTOP_DISABLE) {
3817 /* Not used, and disable higher stages */
3818 break;
3819 }
3820
3821 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3822 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3823 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3824 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3825 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3826 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3827 This->fixed_function_usage_map |= (1 << i);
3828 }
3829
3830 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3831 This->fixed_function_usage_map |= (1 << (i + 1));
3832 }
3833 }
3834}
3835
3836static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3837 unsigned int i, tex;
3838 WORD ffu_map;
3839
3840 device_update_fixed_function_usage_map(This);
3841 ffu_map = This->fixed_function_usage_map;
3842
3843 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3844 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3845 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3846 {
3847 if (!(ffu_map & 1)) continue;
3848
3849 if (This->texUnitMap[i] != i) {
3850 device_map_stage(This, i, i);
3851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3852 markTextureStagesDirty(This, i);
3853 }
3854 }
3855 return;
3856 }
3857
3858 /* Now work out the mapping */
3859 tex = 0;
3860 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3861 {
3862 if (!(ffu_map & 1)) continue;
3863
3864 if (This->texUnitMap[i] != tex) {
3865 device_map_stage(This, i, tex);
3866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3867 markTextureStagesDirty(This, i);
3868 }
3869
3870 ++tex;
3871 }
3872}
3873
3874static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3875 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3876 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3877 unsigned int i;
3878
3879 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3880 if (sampler_type[i] && This->texUnitMap[i] != i)
3881 {
3882 device_map_stage(This, i, i);
3883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3884 if (i < MAX_TEXTURES) {
3885 markTextureStagesDirty(This, i);
3886 }
3887 }
3888 }
3889}
3890
3891static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3892 const DWORD *vshader_sampler_tokens, int unit)
3893{
3894 int current_mapping = This->rev_tex_unit_map[unit];
3895
3896 if (current_mapping == -1) {
3897 /* Not currently used */
3898 return TRUE;
3899 }
3900
3901 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3902 /* Used by a fragment sampler */
3903
3904 if (!pshader_sampler_tokens) {
3905 /* No pixel shader, check fixed function */
3906 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3907 }
3908
3909 /* Pixel shader, check the shader's sampler map */
3910 return !pshader_sampler_tokens[current_mapping];
3911 }
3912
3913 /* Used by a vertex sampler */
3914 return !vshader_sampler_tokens[current_mapping];
3915}
3916
3917static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3918 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3919 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3920 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3921 int start = GL_LIMITS(combined_samplers) - 1;
3922 int i;
3923
3924 if (ps) {
3925 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3926
3927 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3928 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3929 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3930 }
3931
3932 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3933 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3934 if (vshader_sampler_type[i])
3935 {
3936 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3937 {
3938 /* Already mapped somewhere */
3939 continue;
3940 }
3941
3942 while (start >= 0) {
3943 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3944 {
3945 device_map_stage(This, vsampler_idx, start);
3946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3947
3948 --start;
3949 break;
3950 }
3951
3952 --start;
3953 }
3954 }
3955 }
3956}
3957
3958void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3959 BOOL vs = use_vs(This->stateBlock);
3960 BOOL ps = use_ps(This->stateBlock);
3961 /*
3962 * Rules are:
3963 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3964 * that would be really messy and require shader recompilation
3965 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3966 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3967 */
3968 if (ps) {
3969 device_map_psamplers(This);
3970 } else {
3971 device_map_fixed_function_samplers(This);
3972 }
3973
3974 if (vs) {
3975 device_map_vsamplers(This, ps);
3976 }
3977}
3978
3979static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3982 This->updateStateBlock->pixelShader = pShader;
3983 This->updateStateBlock->changed.pixelShader = TRUE;
3984
3985 /* Handle recording of state blocks */
3986 if (This->isRecordingState) {
3987 TRACE("Recording... not performing anything\n");
3988 }
3989
3990 if (This->isRecordingState) {
3991 TRACE("Recording... not performing anything\n");
3992 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3993 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3994 return WINED3D_OK;
3995 }
3996
3997 if(pShader == oldShader) {
3998 TRACE("App is setting the old pixel shader over, nothing to do\n");
3999 return WINED3D_OK;
4000 }
4001
4002 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4003 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4004
4005 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4007
4008 return WINED3D_OK;
4009}
4010
4011static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4013
4014 if (NULL == ppShader) {
4015 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4016 return WINED3DERR_INVALIDCALL;
4017 }
4018
4019 *ppShader = This->stateBlock->pixelShader;
4020 if (NULL != *ppShader) {
4021 IWineD3DPixelShader_AddRef(*ppShader);
4022 }
4023 TRACE("(%p) : returning %p\n", This, *ppShader);
4024 return WINED3D_OK;
4025}
4026
4027static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4028 IWineD3DDevice *iface,
4029 UINT start,
4030 CONST BOOL *srcData,
4031 UINT count) {
4032
4033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4034 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4035
4036 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4037 iface, srcData, start, count);
4038
4039 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4040
4041 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4042 for (i = 0; i < cnt; i++)
4043 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4044
4045 for (i = start; i < cnt + start; ++i) {
4046 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4047 }
4048
4049 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4050
4051 return WINED3D_OK;
4052}
4053
4054static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4055 IWineD3DDevice *iface,
4056 UINT start,
4057 BOOL *dstData,
4058 UINT count) {
4059
4060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4061 int cnt = min(count, MAX_CONST_B - start);
4062
4063 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4064 iface, dstData, start, count);
4065
4066 if (dstData == NULL || cnt < 0)
4067 return WINED3DERR_INVALIDCALL;
4068
4069 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4070 return WINED3D_OK;
4071}
4072
4073static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4074 IWineD3DDevice *iface,
4075 UINT start,
4076 CONST int *srcData,
4077 UINT count) {
4078
4079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4080 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4081
4082 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4083 iface, srcData, start, count);
4084
4085 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4086
4087 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4088 for (i = 0; i < cnt; i++)
4089 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4090 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4091
4092 for (i = start; i < cnt + start; ++i) {
4093 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4094 }
4095
4096 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4097
4098 return WINED3D_OK;
4099}
4100
4101static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4102 IWineD3DDevice *iface,
4103 UINT start,
4104 int *dstData,
4105 UINT count) {
4106
4107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4108 int cnt = min(count, MAX_CONST_I - start);
4109
4110 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4111 iface, dstData, start, count);
4112
4113 if (dstData == NULL || cnt < 0)
4114 return WINED3DERR_INVALIDCALL;
4115
4116 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4117 return WINED3D_OK;
4118}
4119
4120static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4121 IWineD3DDevice *iface,
4122 UINT start,
4123 CONST float *srcData,
4124 UINT count) {
4125
4126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4127 UINT i;
4128
4129 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4130 iface, srcData, start, count);
4131
4132 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4133 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4134 return WINED3DERR_INVALIDCALL;
4135
4136 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4137 if(TRACE_ON(d3d)) {
4138 for (i = 0; i < count; i++)
4139 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4140 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4141 }
4142
4143 if (!This->isRecordingState)
4144 {
4145 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4147 }
4148
4149 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4150 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4151
4152 return WINED3D_OK;
4153}
4154
4155static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4156 IWineD3DDevice *iface,
4157 UINT start,
4158 float *dstData,
4159 UINT count) {
4160
4161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4162 int cnt = min(count, This->d3d_pshader_constantF - start);
4163
4164 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4165 iface, dstData, start, count);
4166
4167 if (dstData == NULL || cnt < 0)
4168 return WINED3DERR_INVALIDCALL;
4169
4170 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4171 return WINED3D_OK;
4172}
4173
4174#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4175static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4176 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4177 DWORD DestFVF)
4178{
4179 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4180 unsigned int i;
4181 WINED3DVIEWPORT vp;
4182 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4183 BOOL doClip;
4184 DWORD numTextures;
4185
4186 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4187 {
4188 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4189 }
4190
4191 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4192 {
4193 ERR("Source has no position mask\n");
4194 return WINED3DERR_INVALIDCALL;
4195 }
4196
4197 /* We might access VBOs from this code, so hold the lock */
4198 ENTER_GL();
4199
4200 if (dest->resource.allocatedMemory == NULL) {
4201 buffer_get_sysmem(dest);
4202 }
4203
4204 /* Get a pointer into the destination vbo(create one if none exists) and
4205 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4206 */
4207 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4208 {
4209 dest->flags |= WINED3D_BUFFER_CREATEBO;
4210 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4211 }
4212
4213 if (dest->buffer_object)
4214 {
4215 unsigned char extrabytes = 0;
4216 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4217 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4218 * this may write 4 extra bytes beyond the area that should be written
4219 */
4220 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4221 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4222 if(!dest_conv_addr) {
4223 ERR("Out of memory\n");
4224 /* Continue without storing converted vertices */
4225 }
4226 dest_conv = dest_conv_addr;
4227 }
4228
4229 /* Should I clip?
4230 * a) WINED3DRS_CLIPPING is enabled
4231 * b) WINED3DVOP_CLIP is passed
4232 */
4233 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4234 static BOOL warned = FALSE;
4235 /*
4236 * The clipping code is not quite correct. Some things need
4237 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4238 * so disable clipping for now.
4239 * (The graphics in Half-Life are broken, and my processvertices
4240 * test crashes with IDirect3DDevice3)
4241 doClip = TRUE;
4242 */
4243 doClip = FALSE;
4244 if(!warned) {
4245 warned = TRUE;
4246 FIXME("Clipping is broken and disabled for now\n");
4247 }
4248 } else doClip = FALSE;
4249 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4250
4251 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4252 WINED3DTS_VIEW,
4253 &view_mat);
4254 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4255 WINED3DTS_PROJECTION,
4256 &proj_mat);
4257 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4258 WINED3DTS_WORLDMATRIX(0),
4259 &world_mat);
4260
4261 TRACE("View mat:\n");
4262 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);
4263 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);
4264 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);
4265 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);
4266
4267 TRACE("Proj mat:\n");
4268 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);
4269 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);
4270 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);
4271 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);
4272
4273 TRACE("World mat:\n");
4274 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);
4275 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);
4276 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);
4277 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);
4278
4279 /* Get the viewport */
4280 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4281 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4282 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4283
4284 multiply_matrix(&mat,&view_mat,&world_mat);
4285 multiply_matrix(&mat,&proj_mat,&mat);
4286
4287 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4288
4289 for (i = 0; i < dwCount; i+= 1) {
4290 unsigned int tex_index;
4291
4292 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4293 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4294 /* The position first */
4295 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4296 const float *p = (const float *)(element->data + i * element->stride);
4297 float x, y, z, rhw;
4298 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4299
4300 /* Multiplication with world, view and projection matrix */
4301 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);
4302 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);
4303 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);
4304 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);
4305
4306 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4307
4308 /* WARNING: The following things are taken from d3d7 and were not yet checked
4309 * against d3d8 or d3d9!
4310 */
4311
4312 /* Clipping conditions: From msdn
4313 *
4314 * A vertex is clipped if it does not match the following requirements
4315 * -rhw < x <= rhw
4316 * -rhw < y <= rhw
4317 * 0 < z <= rhw
4318 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4319 *
4320 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4321 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4322 *
4323 */
4324
4325 if( !doClip ||
4326 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4327 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4328 ( rhw > eps ) ) ) {
4329
4330 /* "Normal" viewport transformation (not clipped)
4331 * 1) The values are divided by rhw
4332 * 2) The y axis is negative, so multiply it with -1
4333 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4334 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4335 * 4) Multiply x with Width/2 and add Width/2
4336 * 5) The same for the height
4337 * 6) Add the viewpoint X and Y to the 2D coordinates and
4338 * The minimum Z value to z
4339 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4340 *
4341 * Well, basically it's simply a linear transformation into viewport
4342 * coordinates
4343 */
4344
4345 x /= rhw;
4346 y /= rhw;
4347 z /= rhw;
4348
4349 y *= -1;
4350
4351 x *= vp.Width / 2;
4352 y *= vp.Height / 2;
4353 z *= vp.MaxZ - vp.MinZ;
4354
4355 x += vp.Width / 2 + vp.X;
4356 y += vp.Height / 2 + vp.Y;
4357 z += vp.MinZ;
4358
4359 rhw = 1 / rhw;
4360 } else {
4361 /* That vertex got clipped
4362 * Contrary to OpenGL it is not dropped completely, it just
4363 * undergoes a different calculation.
4364 */
4365 TRACE("Vertex got clipped\n");
4366 x += rhw;
4367 y += rhw;
4368
4369 x /= 2;
4370 y /= 2;
4371
4372 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4373 * outside of the main vertex buffer memory. That needs some more
4374 * investigation...
4375 */
4376 }
4377
4378 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4379
4380
4381 ( (float *) dest_ptr)[0] = x;
4382 ( (float *) dest_ptr)[1] = y;
4383 ( (float *) dest_ptr)[2] = z;
4384 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4385
4386 dest_ptr += 3 * sizeof(float);
4387
4388 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4389 dest_ptr += sizeof(float);
4390 }
4391
4392 if(dest_conv) {
4393 float w = 1 / rhw;
4394 ( (float *) dest_conv)[0] = x * w;
4395 ( (float *) dest_conv)[1] = y * w;
4396 ( (float *) dest_conv)[2] = z * w;
4397 ( (float *) dest_conv)[3] = w;
4398
4399 dest_conv += 3 * sizeof(float);
4400
4401 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4402 dest_conv += sizeof(float);
4403 }
4404 }
4405 }
4406 if (DestFVF & WINED3DFVF_PSIZE) {
4407 dest_ptr += sizeof(DWORD);
4408 if(dest_conv) dest_conv += sizeof(DWORD);
4409 }
4410 if (DestFVF & WINED3DFVF_NORMAL) {
4411 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4412 const float *normal = (const float *)(element->data + i * element->stride);
4413 /* AFAIK this should go into the lighting information */
4414 FIXME("Didn't expect the destination to have a normal\n");
4415 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4416 if(dest_conv) {
4417 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4418 }
4419 }
4420
4421 if (DestFVF & WINED3DFVF_DIFFUSE) {
4422 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4423 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4424 if(!color_d) {
4425 static BOOL warned = FALSE;
4426
4427 if(!warned) {
4428 ERR("No diffuse color in source, but destination has one\n");
4429 warned = TRUE;
4430 }
4431
4432 *( (DWORD *) dest_ptr) = 0xffffffff;
4433 dest_ptr += sizeof(DWORD);
4434
4435 if(dest_conv) {
4436 *( (DWORD *) dest_conv) = 0xffffffff;
4437 dest_conv += sizeof(DWORD);
4438 }
4439 }
4440 else {
4441 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4442 if(dest_conv) {
4443 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4444 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4445 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4446 dest_conv += sizeof(DWORD);
4447 }
4448 }
4449 }
4450
4451 if (DestFVF & WINED3DFVF_SPECULAR) {
4452 /* What's the color value in the feedback buffer? */
4453 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4454 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4455 if(!color_s) {
4456 static BOOL warned = FALSE;
4457
4458 if(!warned) {
4459 ERR("No specular color in source, but destination has one\n");
4460 warned = TRUE;
4461 }
4462
4463 *( (DWORD *) dest_ptr) = 0xFF000000;
4464 dest_ptr += sizeof(DWORD);
4465
4466 if(dest_conv) {
4467 *( (DWORD *) dest_conv) = 0xFF000000;
4468 dest_conv += sizeof(DWORD);
4469 }
4470 }
4471 else {
4472 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4473 if(dest_conv) {
4474 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4475 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4476 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4477 dest_conv += sizeof(DWORD);
4478 }
4479 }
4480 }
4481
4482 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4483 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4484 const float *tex_coord = (const float *)(element->data + i * element->stride);
4485 if(!tex_coord) {
4486 ERR("No source texture, but destination requests one\n");
4487 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4488 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4489 }
4490 else {
4491 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4492 if(dest_conv) {
4493 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4494 }
4495 }
4496 }
4497 }
4498
4499 if(dest_conv) {
4500 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4501 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4502 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4503 dwCount * get_flexible_vertex_size(DestFVF),
4504 dest_conv_addr));
4505 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4506 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4507 }
4508
4509 LEAVE_GL();
4510
4511 return WINED3D_OK;
4512}
4513#undef copy_and_next
4514
4515static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4516 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4517 DWORD DestFVF)
4518{
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 struct wined3d_stream_info stream_info;
4521 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4522 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4523
4524 if(pVertexDecl) {
4525 ERR("Output vertex declaration not implemented yet\n");
4526 }
4527
4528 /* Need any context to write to the vbo. */
4529 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4530
4531 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4532 * control the streamIsUP flag, thus restore it afterwards.
4533 */
4534 This->stateBlock->streamIsUP = FALSE;
4535 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4536 This->stateBlock->streamIsUP = streamWasUP;
4537
4538 if(vbo || SrcStartIndex) {
4539 unsigned int i;
4540 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4541 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4542 *
4543 * Also get the start index in, but only loop over all elements if there's something to add at all.
4544 */
4545 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4546 {
4547 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4548 if (e->buffer_object)
4549 {
4550 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4551 e->buffer_object = 0;
4552 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4553 ENTER_GL();
4554 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4555 vb->buffer_object = 0;
4556 LEAVE_GL();
4557 }
4558 if (e->data) e->data += e->stride * SrcStartIndex;
4559 }
4560 }
4561
4562 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4563 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4564}
4565
4566/*****
4567 * Get / Set Texture Stage States
4568 * TODO: Verify against dx9 definitions
4569 *****/
4570static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4573
4574 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4575
4576 if (Stage >= MAX_TEXTURES) {
4577 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4578 return WINED3D_OK;
4579 }
4580
4581 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4582 This->updateStateBlock->textureState[Stage][Type] = Value;
4583
4584 if (This->isRecordingState) {
4585 TRACE("Recording... not performing anything\n");
4586 return WINED3D_OK;
4587 }
4588
4589 /* Checked after the assignments to allow proper stateblock recording */
4590 if(oldValue == Value) {
4591 TRACE("App is setting the old value over, nothing to do\n");
4592 return WINED3D_OK;
4593 }
4594
4595 if(Stage > This->stateBlock->lowest_disabled_stage &&
4596 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4597 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4598 * Changes in other states are important on disabled stages too
4599 */
4600 return WINED3D_OK;
4601 }
4602
4603 if(Type == WINED3DTSS_COLOROP) {
4604 unsigned int i;
4605
4606 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4607 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4608 * they have to be disabled
4609 *
4610 * The current stage is dirtified below.
4611 */
4612 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4613 TRACE("Additionally dirtifying stage %u\n", i);
4614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4615 }
4616 This->stateBlock->lowest_disabled_stage = Stage;
4617 TRACE("New lowest disabled: %u\n", Stage);
4618 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4619 /* Previously disabled stage enabled. Stages above it may need enabling
4620 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4621 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4622 *
4623 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4624 */
4625
4626 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4627 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4628 break;
4629 }
4630 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4632 }
4633 This->stateBlock->lowest_disabled_stage = i;
4634 TRACE("New lowest disabled: %u\n", i);
4635 }
4636 }
4637
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4639
4640 return WINED3D_OK;
4641}
4642
4643static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4646 *pValue = This->updateStateBlock->textureState[Stage][Type];
4647 return WINED3D_OK;
4648}
4649
4650/*****
4651 * Get / Set Texture
4652 *****/
4653static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 IWineD3DBaseTexture *oldTexture;
4656
4657 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4658
4659 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4660 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4661 }
4662
4663 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4664 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4665 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4666 }
4667
4668 oldTexture = This->updateStateBlock->textures[Stage];
4669
4670 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4671 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4672 {
4673 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4674 return WINED3DERR_INVALIDCALL;
4675 }
4676
4677 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4678 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4679
4680 This->updateStateBlock->changed.textures |= 1 << Stage;
4681 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4682 This->updateStateBlock->textures[Stage] = pTexture;
4683
4684 /* Handle recording of state blocks */
4685 if (This->isRecordingState) {
4686 TRACE("Recording... not performing anything\n");
4687 return WINED3D_OK;
4688 }
4689
4690 if(oldTexture == pTexture) {
4691 TRACE("App is setting the same texture again, nothing to do\n");
4692 return WINED3D_OK;
4693 }
4694
4695 /** NOTE: MSDN says that setTexture increases the reference count,
4696 * and that the application must set the texture back to null (or have a leaky application),
4697 * This means we should pass the refcount up to the parent
4698 *******************************/
4699 if (NULL != This->updateStateBlock->textures[Stage]) {
4700 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4701 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4702 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4703
4704 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4705
4706 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4707 {
4708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4709 }
4710
4711 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4712 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4713 * so the COLOROP and ALPHAOP have to be dirtified.
4714 */
4715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4717 }
4718 if(bindCount == 1) {
4719 new->baseTexture.sampler = Stage;
4720 }
4721 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4722
4723 }
4724
4725 if (NULL != oldTexture) {
4726 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4727 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4728
4729 IWineD3DBaseTexture_Release(oldTexture);
4730 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4733 }
4734
4735 if(bindCount && old->baseTexture.sampler == Stage) {
4736 int i;
4737 /* Have to do a search for the other sampler(s) where the texture is bound to
4738 * Shouldn't happen as long as apps bind a texture only to one stage
4739 */
4740 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4741 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4742 if(This->updateStateBlock->textures[i] == oldTexture) {
4743 old->baseTexture.sampler = i;
4744 break;
4745 }
4746 }
4747 }
4748 }
4749
4750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4751
4752 return WINED3D_OK;
4753}
4754
4755static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757
4758 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4759
4760 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4761 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4762 }
4763
4764 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4765 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4766 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4767 }
4768
4769 *ppTexture=This->stateBlock->textures[Stage];
4770 if (*ppTexture)
4771 IWineD3DBaseTexture_AddRef(*ppTexture);
4772
4773 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4774
4775 return WINED3D_OK;
4776}
4777
4778/*****
4779 * Get Back Buffer
4780 *****/
4781static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4782 IWineD3DSurface **ppBackBuffer) {
4783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4784 IWineD3DSwapChain *swapChain;
4785 HRESULT hr;
4786
4787 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4788
4789 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4790 if (hr == WINED3D_OK) {
4791 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4792 IWineD3DSwapChain_Release(swapChain);
4793 } else {
4794 *ppBackBuffer = NULL;
4795 }
4796 return hr;
4797}
4798
4799static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 WARN("(%p) : stub, calling idirect3d for now\n", This);
4802 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4803}
4804
4805static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 IWineD3DSwapChain *swapChain;
4808 HRESULT hr;
4809
4810 if(iSwapChain > 0) {
4811 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4812 if (hr == WINED3D_OK) {
4813 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4814 IWineD3DSwapChain_Release(swapChain);
4815 } else {
4816 FIXME("(%p) Error getting display mode\n", This);
4817 }
4818 } else {
4819 /* Don't read the real display mode,
4820 but return the stored mode instead. X11 can't change the color
4821 depth, and some apps are pretty angry if they SetDisplayMode from
4822 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4823
4824 Also don't relay to the swapchain because with ddraw it's possible
4825 that there isn't a swapchain at all */
4826 pMode->Width = This->ddraw_width;
4827 pMode->Height = This->ddraw_height;
4828 pMode->Format = This->ddraw_format;
4829 pMode->RefreshRate = 0;
4830 hr = WINED3D_OK;
4831 }
4832
4833 return hr;
4834}
4835
4836/*****
4837 * Stateblock related functions
4838 *****/
4839
4840static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 IWineD3DStateBlock *stateblock;
4843 HRESULT hr;
4844
4845 TRACE("(%p)\n", This);
4846
4847 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4848
4849 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4850 if (FAILED(hr)) return hr;
4851
4852 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4853 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4854 This->isRecordingState = TRUE;
4855
4856 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4857
4858 return WINED3D_OK;
4859}
4860
4861static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4863 unsigned int i, j;
4864 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4865
4866 if (!This->isRecordingState) {
4867 WARN("(%p) not recording! returning error\n", This);
4868 *ppStateBlock = NULL;
4869 return WINED3DERR_INVALIDCALL;
4870 }
4871
4872 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4873 {
4874 DWORD map = object->changed.renderState[i];
4875 for (j = 0; map; map >>= 1, ++j)
4876 {
4877 if (!(map & 1)) continue;
4878
4879 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4880 }
4881 }
4882
4883 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4884 {
4885 DWORD map = object->changed.transform[i];
4886 for (j = 0; map; map >>= 1, ++j)
4887 {
4888 if (!(map & 1)) continue;
4889
4890 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4891 }
4892 }
4893 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4894 if(object->changed.vertexShaderConstantsF[i]) {
4895 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4896 object->num_contained_vs_consts_f++;
4897 }
4898 }
4899 for(i = 0; i < MAX_CONST_I; i++) {
4900 if (object->changed.vertexShaderConstantsI & (1 << i))
4901 {
4902 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4903 object->num_contained_vs_consts_i++;
4904 }
4905 }
4906 for(i = 0; i < MAX_CONST_B; i++) {
4907 if (object->changed.vertexShaderConstantsB & (1 << i))
4908 {
4909 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4910 object->num_contained_vs_consts_b++;
4911 }
4912 }
4913 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4914 {
4915 if (object->changed.pixelShaderConstantsF[i])
4916 {
4917 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4918 ++object->num_contained_ps_consts_f;
4919 }
4920 }
4921 for(i = 0; i < MAX_CONST_I; i++) {
4922 if (object->changed.pixelShaderConstantsI & (1 << i))
4923 {
4924 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4925 object->num_contained_ps_consts_i++;
4926 }
4927 }
4928 for(i = 0; i < MAX_CONST_B; i++) {
4929 if (object->changed.pixelShaderConstantsB & (1 << i))
4930 {
4931 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4932 object->num_contained_ps_consts_b++;
4933 }
4934 }
4935 for(i = 0; i < MAX_TEXTURES; i++) {
4936 DWORD map = object->changed.textureState[i];
4937
4938 for(j = 0; map; map >>= 1, ++j)
4939 {
4940 if (!(map & 1)) continue;
4941
4942 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4943 object->contained_tss_states[object->num_contained_tss_states].state = j;
4944 ++object->num_contained_tss_states;
4945 }
4946 }
4947 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4948 DWORD map = object->changed.samplerState[i];
4949
4950 for (j = 0; map; map >>= 1, ++j)
4951 {
4952 if (!(map & 1)) continue;
4953
4954 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4955 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4956 ++object->num_contained_sampler_states;
4957 }
4958 }
4959
4960 *ppStateBlock = (IWineD3DStateBlock*) object;
4961 This->isRecordingState = FALSE;
4962 This->updateStateBlock = This->stateBlock;
4963 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4964 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4965 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4966 return WINED3D_OK;
4967}
4968
4969/*****
4970 * Scene related functions
4971 *****/
4972static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4973 /* At the moment we have no need for any functionality at the beginning
4974 of a scene */
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4976 TRACE("(%p)\n", This);
4977
4978 if(This->inScene) {
4979 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4980 return WINED3DERR_INVALIDCALL;
4981 }
4982 This->inScene = TRUE;
4983 return WINED3D_OK;
4984}
4985
4986static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 TRACE("(%p)\n", This);
4989
4990 if(!This->inScene) {
4991 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4992 return WINED3DERR_INVALIDCALL;
4993 }
4994
4995 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4996 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4997 glFlush();
4998 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4999 * fails
5000 */
5001
5002 This->inScene = FALSE;
5003 return WINED3D_OK;
5004}
5005
5006static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5007 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5008 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5010 IWineD3DSwapChain *swapChain = NULL;
5011 int i;
5012 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5013
5014 TRACE("(%p) Presenting the frame\n", This);
5015
5016 for(i = 0 ; i < swapchains ; i ++) {
5017
5018 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5019 TRACE("presentinng chain %d, %p\n", i, swapChain);
5020 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5021 IWineD3DSwapChain_Release(swapChain);
5022 }
5023
5024 return WINED3D_OK;
5025}
5026
5027/* Not called from the VTable (internal subroutine) */
5028HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5029 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5030 float Z, DWORD Stencil) {
5031 GLbitfield glMask = 0;
5032 unsigned int i;
5033 WINED3DRECT curRect;
5034 RECT vp_rect;
5035 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5036 UINT drawable_width, drawable_height;
5037 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5038 IWineD3DSwapChainImpl *swapchain = NULL;
5039
5040 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5041 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5042 * for the cleared parts, and the untouched parts.
5043 *
5044 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5045 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5046 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5047 * checking all this if the dest surface is in the drawable anyway.
5048 */
5049 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5050 while(1) {
5051 if(vp->X != 0 || vp->Y != 0 ||
5052 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5053 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5054 break;
5055 }
5056 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5057 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5058 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5059 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5060 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5061 break;
5062 }
5063 if(Count > 0 && pRects && (
5064 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5065 pRects[0].x2 < target->currentDesc.Width ||
5066 pRects[0].y2 < target->currentDesc.Height)) {
5067 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5068 break;
5069 }
5070 break;
5071 }
5072 }
5073
5074 target->get_drawable_size(target, &drawable_width, &drawable_height);
5075
5076 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5077 ENTER_GL();
5078
5079 /* Only set the values up once, as they are not changing */
5080 if (Flags & WINED3DCLEAR_STENCIL) {
5081 glClearStencil(Stencil);
5082 checkGLcall("glClearStencil");
5083 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5084 glStencilMask(0xFFFFFFFF);
5085 }
5086
5087 if (Flags & WINED3DCLEAR_ZBUFFER) {
5088 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5089 glDepthMask(GL_TRUE);
5090 glClearDepth(Z);
5091 checkGLcall("glClearDepth");
5092 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5094
5095 if (vp->X != 0 || vp->Y != 0 ||
5096 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5097 surface_load_ds_location(This->stencilBufferTarget, location);
5098 }
5099 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5100 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5101 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5102 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5103 surface_load_ds_location(This->stencilBufferTarget, location);
5104 }
5105 else if (Count > 0 && pRects && (
5106 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5107 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5108 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5109 surface_load_ds_location(This->stencilBufferTarget, location);
5110 }
5111 }
5112
5113 if (Flags & WINED3DCLEAR_TARGET) {
5114 TRACE("Clearing screen with glClear to color %x\n", Color);
5115 glClearColor(D3DCOLOR_R(Color),
5116 D3DCOLOR_G(Color),
5117 D3DCOLOR_B(Color),
5118 D3DCOLOR_A(Color));
5119 checkGLcall("glClearColor");
5120
5121 /* Clear ALL colors! */
5122 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5123 glMask = glMask | GL_COLOR_BUFFER_BIT;
5124 }
5125
5126 vp_rect.left = vp->X;
5127 vp_rect.top = vp->Y;
5128 vp_rect.right = vp->X + vp->Width;
5129 vp_rect.bottom = vp->Y + vp->Height;
5130 if (!(Count > 0 && pRects)) {
5131 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5132 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5133 }
5134 if(This->render_offscreen) {
5135 glScissor(vp_rect.left, vp_rect.top,
5136 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5137 } else {
5138 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5139 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5140 }
5141 checkGLcall("glScissor");
5142 glClear(glMask);
5143 checkGLcall("glClear");
5144 } else {
5145 /* Now process each rect in turn */
5146 for (i = 0; i < Count; i++) {
5147 /* Note gl uses lower left, width/height */
5148 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5149 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5150 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5151 }
5152 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5153 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5154 curRect.x1, (target->currentDesc.Height - curRect.y2),
5155 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5156
5157 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5158 * The rectangle is not cleared, no error is returned, but further rectanlges are
5159 * still cleared if they are valid
5160 */
5161 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5162 TRACE("Rectangle with negative dimensions, ignoring\n");
5163 continue;
5164 }
5165
5166 if(This->render_offscreen) {
5167 glScissor(curRect.x1, curRect.y1,
5168 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5169 } else {
5170 glScissor(curRect.x1, drawable_height - curRect.y2,
5171 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5172 }
5173 checkGLcall("glScissor");
5174
5175 glClear(glMask);
5176 checkGLcall("glClear");
5177 }
5178 }
5179
5180 /* Restore the old values (why..?) */
5181 if (Flags & WINED3DCLEAR_STENCIL) {
5182 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5183 }
5184 if (Flags & WINED3DCLEAR_TARGET) {
5185 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5186 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5187 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5188 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5189 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5190
5191 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5192 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5193 */
5194 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5195 }
5196 if (Flags & WINED3DCLEAR_ZBUFFER) {
5197 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5198 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5199 surface_modify_ds_location(This->stencilBufferTarget, location);
5200 }
5201
5202 LEAVE_GL();
5203
5204 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5205 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5206 glFlush();
5207 }
5208 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5209 }
5210
5211 return WINED3D_OK;
5212}
5213
5214static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5215 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5217 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5218
5219 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5220 Count, pRects, Flags, Color, Z, Stencil);
5221
5222 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5223 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5224 /* TODO: What about depth stencil buffers without stencil bits? */
5225 return WINED3DERR_INVALIDCALL;
5226 }
5227
5228 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5229}
5230
5231/*****
5232 * Drawing functions
5233 *****/
5234
5235static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5236 WINED3DPRIMITIVETYPE primitive_type)
5237{
5238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5239
5240 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5241
5242 This->updateStateBlock->changed.primitive_type = TRUE;
5243 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5244}
5245
5246static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5247 WINED3DPRIMITIVETYPE *primitive_type)
5248{
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250
5251 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5252
5253 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5254
5255 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5256}
5257
5258static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5259{
5260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5261
5262 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5263
5264 if(!This->stateBlock->vertexDecl) {
5265 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5266 return WINED3DERR_INVALIDCALL;
5267 }
5268
5269 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5270 if(This->stateBlock->streamIsUP) {
5271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5272 This->stateBlock->streamIsUP = FALSE;
5273 }
5274
5275 if(This->stateBlock->loadBaseVertexIndex != 0) {
5276 This->stateBlock->loadBaseVertexIndex = 0;
5277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5278 }
5279 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5280 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5281 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5282 return WINED3D_OK;
5283}
5284
5285static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5286 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5287{
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 UINT idxStride = 2;
5290 IWineD3DBuffer *pIB;
5291 GLuint vbo;
5292
5293 pIB = This->stateBlock->pIndexData;
5294 if (!pIB) {
5295 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5296 * without an index buffer set. (The first time at least...)
5297 * D3D8 simply dies, but I doubt it can do much harm to return
5298 * D3DERR_INVALIDCALL there as well. */
5299 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5300 return WINED3DERR_INVALIDCALL;
5301 }
5302
5303 if(!This->stateBlock->vertexDecl) {
5304 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5305 return WINED3DERR_INVALIDCALL;
5306 }
5307
5308 if(This->stateBlock->streamIsUP) {
5309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5310 This->stateBlock->streamIsUP = FALSE;
5311 }
5312 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5313
5314 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5315 This, minIndex, NumVertices, startIndex, index_count);
5316
5317 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5318 idxStride = 2;
5319 } else {
5320 idxStride = 4;
5321 }
5322
5323 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5324 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5326 }
5327
5328 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5329 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5330
5331 return WINED3D_OK;
5332}
5333
5334static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5335 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5336{
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 IWineD3DBuffer *vb;
5339
5340 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5341 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5342
5343 if(!This->stateBlock->vertexDecl) {
5344 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5345 return WINED3DERR_INVALIDCALL;
5346 }
5347
5348 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5349 vb = This->stateBlock->streamSource[0];
5350 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5351 if (vb) IWineD3DBuffer_Release(vb);
5352 This->stateBlock->streamOffset[0] = 0;
5353 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5354 This->stateBlock->streamIsUP = TRUE;
5355 This->stateBlock->loadBaseVertexIndex = 0;
5356
5357 /* TODO: Only mark dirty if drawing from a different UP address */
5358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5359
5360 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5361 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5362
5363 /* MSDN specifies stream zero settings must be set to NULL */
5364 This->stateBlock->streamStride[0] = 0;
5365 This->stateBlock->streamSource[0] = NULL;
5366
5367 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5368 * the new stream sources or use UP drawing again
5369 */
5370 return WINED3D_OK;
5371}
5372
5373static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5374 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5375 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5376{
5377 int idxStride;
5378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5379 IWineD3DBuffer *vb;
5380 IWineD3DBuffer *ib;
5381
5382 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5383 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5384 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5385
5386 if(!This->stateBlock->vertexDecl) {
5387 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5388 return WINED3DERR_INVALIDCALL;
5389 }
5390
5391 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5392 idxStride = 2;
5393 } else {
5394 idxStride = 4;
5395 }
5396
5397 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5398 vb = This->stateBlock->streamSource[0];
5399 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5400 if (vb) IWineD3DBuffer_Release(vb);
5401 This->stateBlock->streamIsUP = TRUE;
5402 This->stateBlock->streamOffset[0] = 0;
5403 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5404
5405 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5406 This->stateBlock->baseVertexIndex = 0;
5407 This->stateBlock->loadBaseVertexIndex = 0;
5408 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5411
5412 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5413 idxStride, pIndexData, MinVertexIndex);
5414
5415 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5416 This->stateBlock->streamSource[0] = NULL;
5417 This->stateBlock->streamStride[0] = 0;
5418 ib = This->stateBlock->pIndexData;
5419 if(ib) {
5420 IWineD3DBuffer_Release(ib);
5421 This->stateBlock->pIndexData = NULL;
5422 }
5423 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5424 * SetStreamSource to specify a vertex buffer
5425 */
5426
5427 return WINED3D_OK;
5428}
5429
5430static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5431 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5432{
5433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5434
5435 /* Mark the state dirty until we have nicer tracking
5436 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5437 * that value.
5438 */
5439 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5441 This->stateBlock->baseVertexIndex = 0;
5442 This->up_strided = DrawPrimStrideData;
5443 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5444 This->up_strided = NULL;
5445 return WINED3D_OK;
5446}
5447
5448static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5449 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5450 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5451{
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5453 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5454
5455 /* Mark the state dirty until we have nicer tracking
5456 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5457 * that value.
5458 */
5459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5461 This->stateBlock->streamIsUP = TRUE;
5462 This->stateBlock->baseVertexIndex = 0;
5463 This->up_strided = DrawPrimStrideData;
5464 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5465 This->up_strided = NULL;
5466 return WINED3D_OK;
5467}
5468
5469static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5470 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5471 * not callable by the app directly no parameter validation checks are needed here.
5472 */
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5474 WINED3DLOCKED_BOX src;
5475 WINED3DLOCKED_BOX dst;
5476 HRESULT hr;
5477 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5478
5479 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5480 * dirtification to improve loading performance.
5481 */
5482 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5483 if(FAILED(hr)) return hr;
5484 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5485 if(FAILED(hr)) {
5486 IWineD3DVolume_UnlockBox(pSourceVolume);
5487 return hr;
5488 }
5489
5490 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5491
5492 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5493 if(FAILED(hr)) {
5494 IWineD3DVolume_UnlockBox(pSourceVolume);
5495 } else {
5496 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5497 }
5498 return hr;
5499}
5500
5501/* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5502static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5504 HRESULT hr = WINED3D_OK;
5505 WINED3DRESOURCETYPE sourceType;
5506 WINED3DRESOURCETYPE destinationType;
5507 int i ,levels;
5508
5509 /* TODO: think about moving the code into IWineD3DBaseTexture */
5510
5511 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5512
5513 /* verify that the source and destination textures aren't NULL */
5514 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5515 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5516 This, pSourceTexture, pDestinationTexture);
5517 hr = WINED3DERR_INVALIDCALL;
5518 }
5519
5520 if (pSourceTexture == pDestinationTexture) {
5521 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5522 This, pSourceTexture, pDestinationTexture);
5523 hr = WINED3DERR_INVALIDCALL;
5524 }
5525 /* Verify that the source and destination textures are the same type */
5526 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5527 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5528
5529 if (sourceType != destinationType) {
5530 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5531 This);
5532 hr = WINED3DERR_INVALIDCALL;
5533 }
5534
5535 /* check that both textures have the identical numbers of levels */
5536 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5537 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5538 hr = WINED3DERR_INVALIDCALL;
5539 }
5540
5541 if (WINED3D_OK == hr) {
5542 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5543
5544 /* Make sure that the destination texture is loaded */
5545 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5546
5547 /* Update every surface level of the texture */
5548 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5549
5550 switch (sourceType) {
5551 case WINED3DRTYPE_TEXTURE:
5552 {
5553 IWineD3DSurface *srcSurface;
5554 IWineD3DSurface *destSurface;
5555
5556 for (i = 0 ; i < levels ; ++i) {
5557 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5558 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5559 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5560 IWineD3DSurface_Release(srcSurface);
5561 IWineD3DSurface_Release(destSurface);
5562 if (WINED3D_OK != hr) {
5563 WARN("(%p) : Call to update surface failed\n", This);
5564 return hr;
5565 }
5566 }
5567 }
5568 break;
5569 case WINED3DRTYPE_CUBETEXTURE:
5570 {
5571 IWineD3DSurface *srcSurface;
5572 IWineD3DSurface *destSurface;
5573 WINED3DCUBEMAP_FACES faceType;
5574
5575 for (i = 0 ; i < levels ; ++i) {
5576 /* Update each cube face */
5577 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5578 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5579 if (WINED3D_OK != hr) {
5580 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5581 } else {
5582 TRACE("Got srcSurface %p\n", srcSurface);
5583 }
5584 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5585 if (WINED3D_OK != hr) {
5586 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5587 } else {
5588 TRACE("Got desrSurface %p\n", destSurface);
5589 }
5590 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5591 IWineD3DSurface_Release(srcSurface);
5592 IWineD3DSurface_Release(destSurface);
5593 if (WINED3D_OK != hr) {
5594 WARN("(%p) : Call to update surface failed\n", This);
5595 return hr;
5596 }
5597 }
5598 }
5599 }
5600 break;
5601
5602 case WINED3DRTYPE_VOLUMETEXTURE:
5603 {
5604 IWineD3DVolume *srcVolume = NULL;
5605 IWineD3DVolume *destVolume = NULL;
5606
5607 for (i = 0 ; i < levels ; ++i) {
5608 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5609 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5610 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5611 IWineD3DVolume_Release(srcVolume);
5612 IWineD3DVolume_Release(destVolume);
5613 if (WINED3D_OK != hr) {
5614 WARN("(%p) : Call to update volume failed\n", This);
5615 return hr;
5616 }
5617 }
5618 }
5619 break;
5620
5621 default:
5622 FIXME("(%p) : Unsupported source and destination type\n", This);
5623 hr = WINED3DERR_INVALIDCALL;
5624 }
5625 }
5626
5627 return hr;
5628}
5629
5630static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5631 IWineD3DSwapChain *swapChain;
5632 HRESULT hr;
5633 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5634 if(hr == WINED3D_OK) {
5635 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5636 IWineD3DSwapChain_Release(swapChain);
5637 }
5638 return hr;
5639}
5640
5641static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 IWineD3DBaseTextureImpl *texture;
5644 DWORD i;
5645
5646 TRACE("(%p) : %p\n", This, pNumPasses);
5647
5648 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5649 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5650 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5651 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5652 }
5653 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5654 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5655 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5656 }
5657
5658 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5659 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5660
5661 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5662 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5663 return E_FAIL;
5664 }
5665 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5666 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5667 return E_FAIL;
5668 }
5669 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5670 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5671 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5672 return E_FAIL;
5673 }
5674 }
5675
5676 /* return a sensible default */
5677 *pNumPasses = 1;
5678
5679 TRACE("returning D3D_OK\n");
5680 return WINED3D_OK;
5681}
5682
5683static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5684{
5685 int i;
5686
5687 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5688 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5689 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5690 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5691 {
5692 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5693 }
5694 }
5695}
5696
5697static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5699 int j;
5700 UINT NewSize;
5701 PALETTEENTRY **palettes;
5702
5703 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5704
5705 if (PaletteNumber >= MAX_PALETTES) {
5706 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5707 return WINED3DERR_INVALIDCALL;
5708 }
5709
5710 if (PaletteNumber >= This->NumberOfPalettes) {
5711 NewSize = This->NumberOfPalettes;
5712 do {
5713 NewSize *= 2;
5714 } while(PaletteNumber >= NewSize);
5715 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5716 if (!palettes) {
5717 ERR("Out of memory!\n");
5718 return E_OUTOFMEMORY;
5719 }
5720 This->palettes = palettes;
5721 This->NumberOfPalettes = NewSize;
5722 }
5723
5724 if (!This->palettes[PaletteNumber]) {
5725 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5726 if (!This->palettes[PaletteNumber]) {
5727 ERR("Out of memory!\n");
5728 return E_OUTOFMEMORY;
5729 }
5730 }
5731
5732 for (j = 0; j < 256; ++j) {
5733 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5734 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5735 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5736 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5737 }
5738 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5739 TRACE("(%p) : returning\n", This);
5740 return WINED3D_OK;
5741}
5742
5743static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 int j;
5746 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5747 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5748 /* What happens in such situation isn't documented; Native seems to silently abort
5749 on such conditions. Return Invalid Call. */
5750 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5751 return WINED3DERR_INVALIDCALL;
5752 }
5753 for (j = 0; j < 256; ++j) {
5754 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5755 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5756 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5757 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5758 }
5759 TRACE("(%p) : returning\n", This);
5760 return WINED3D_OK;
5761}
5762
5763static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5765 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5766 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5767 (tested with reference rasterizer). Return Invalid Call. */
5768 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5769 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5770 return WINED3DERR_INVALIDCALL;
5771 }
5772 /*TODO: stateblocks */
5773 if (This->currentPalette != PaletteNumber) {
5774 This->currentPalette = PaletteNumber;
5775 dirtify_p8_texture_samplers(This);
5776 }
5777 TRACE("(%p) : returning\n", This);
5778 return WINED3D_OK;
5779}
5780
5781static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5783 if (PaletteNumber == NULL) {
5784 WARN("(%p) : returning Invalid Call\n", This);
5785 return WINED3DERR_INVALIDCALL;
5786 }
5787 /*TODO: stateblocks */
5788 *PaletteNumber = This->currentPalette;
5789 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5790 return WINED3D_OK;
5791}
5792
5793static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5795 static BOOL warned;
5796 if (!warned)
5797 {
5798 FIXME("(%p) : stub\n", This);
5799 warned = TRUE;
5800 }
5801
5802 This->softwareVertexProcessing = bSoftware;
5803 return WINED3D_OK;
5804}
5805
5806
5807static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 static BOOL warned;
5810 if (!warned)
5811 {
5812 FIXME("(%p) : stub\n", This);
5813 warned = TRUE;
5814 }
5815 return This->softwareVertexProcessing;
5816}
5817
5818
5819static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5821 IWineD3DSwapChain *swapChain;
5822 HRESULT hr;
5823
5824 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5825
5826 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5827 if(hr == WINED3D_OK){
5828 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5829 IWineD3DSwapChain_Release(swapChain);
5830 }else{
5831 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5832 }
5833 return hr;
5834}
5835
5836
5837static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5839 static BOOL warned;
5840 if(nSegments != 0.0f) {
5841 if (!warned)
5842 {
5843 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5844 warned = TRUE;
5845 }
5846 }
5847 return WINED3D_OK;
5848}
5849
5850static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5852 static BOOL warned;
5853 if (!warned)
5854 {
5855 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5856 warned = TRUE;
5857 }
5858 return 0.0f;
5859}
5860
5861static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5863 /** TODO: remove casts to IWineD3DSurfaceImpl
5864 * NOTE: move code to surface to accomplish this
5865 ****************************************/
5866 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5867 int srcWidth, srcHeight;
5868 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5869 WINED3DFORMAT destFormat, srcFormat;
5870 UINT destSize;
5871 int srcLeft, destLeft, destTop;
5872 WINED3DPOOL srcPool, destPool;
5873 int offset = 0;
5874 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5875 glDescriptor *glDescription = NULL;
5876 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5877 GLenum dummy;
5878 int sampler;
5879 int bpp;
5880 CONVERT_TYPES convert = NO_CONVERSION;
5881
5882 WINED3DSURFACE_DESC winedesc;
5883
5884 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5885 memset(&winedesc, 0, sizeof(winedesc));
5886 winedesc.Width = &srcSurfaceWidth;
5887 winedesc.Height = &srcSurfaceHeight;
5888 winedesc.Pool = &srcPool;
5889 winedesc.Format = &srcFormat;
5890
5891 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5892
5893 winedesc.Width = &destSurfaceWidth;
5894 winedesc.Height = &destSurfaceHeight;
5895 winedesc.Pool = &destPool;
5896 winedesc.Format = &destFormat;
5897 winedesc.Size = &destSize;
5898
5899 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5900
5901 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5902 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5903 return WINED3DERR_INVALIDCALL;
5904 }
5905
5906 /* This call loads the opengl surface directly, instead of copying the surface to the
5907 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5908 * copy in sysmem and use regular surface loading.
5909 */
5910 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5911 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5912 if(convert != NO_CONVERSION) {
5913 return IWineD3DSurface_BltFast(pDestinationSurface,
5914 pDestPoint ? pDestPoint->x : 0,
5915 pDestPoint ? pDestPoint->y : 0,
5916 pSourceSurface, pSourceRect, 0);
5917 }
5918
5919 if (destFormat == WINED3DFMT_UNKNOWN) {
5920 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5921 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5922
5923 /* Get the update surface description */
5924 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5925 }
5926
5927 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5928
5929 ENTER_GL();
5930 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5931 checkGLcall("glActiveTextureARB");
5932 LEAVE_GL();
5933
5934 /* Make sure the surface is loaded and up to date */
5935 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5936 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5937
5938 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5939
5940 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5941 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5942
5943 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5944 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5945 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5946 srcLeft = pSourceRect ? pSourceRect->left : 0;
5947 destLeft = pDestPoint ? pDestPoint->x : 0;
5948 destTop = pDestPoint ? pDestPoint->y : 0;
5949
5950
5951 /* This function doesn't support compressed textures
5952 the pitch is just bytesPerPixel * width */
5953 if(srcWidth != srcSurfaceWidth || srcLeft ){
5954 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5955 offset += srcLeft * src_format_desc->byte_count;
5956 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5957 }
5958 /* TODO DXT formats */
5959
5960 if(pSourceRect != NULL && pSourceRect->top != 0){
5961 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5962 }
5963 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5964 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5965 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5966
5967 /* Sanity check */
5968 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5969
5970 /* need to lock the surface to get the data */
5971 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5972 }
5973
5974 ENTER_GL();
5975
5976 /* TODO: Cube and volume support */
5977 if(rowoffset != 0){
5978 /* not a whole row so we have to do it a line at a time */
5979 int j;
5980
5981 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5982 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5983
5984 for (j = destTop; j < (srcHeight + destTop); ++j)
5985 {
5986 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5987 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5988 data += rowoffset;
5989 }
5990
5991 } else { /* Full width, so just write out the whole texture */
5992 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5993
5994 if (WINED3DFMT_DXT1 == destFormat ||
5995 WINED3DFMT_DXT2 == destFormat ||
5996 WINED3DFMT_DXT3 == destFormat ||
5997 WINED3DFMT_DXT4 == destFormat ||
5998 WINED3DFMT_DXT5 == destFormat) {
5999 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6000 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6001 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6002 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6003 } if (destFormat != srcFormat) {
6004 FIXME("Updating mixed format compressed texture is not curretly support\n");
6005 } else {
6006 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6007 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6008 }
6009 } else {
6010 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6011 }
6012
6013
6014 } else {
6015 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6016 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6017 }
6018 }
6019 checkGLcall("glTexSubImage2D");
6020
6021 LEAVE_GL();
6022
6023 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6024 sampler = This->rev_tex_unit_map[0];
6025 if (sampler != -1) {
6026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6027 }
6028
6029 return WINED3D_OK;
6030}
6031
6032static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6034 struct WineD3DRectPatch *patch;
6035 GLenum old_primitive_type;
6036 unsigned int i;
6037 struct list *e;
6038 BOOL found;
6039 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6040
6041 if(!(Handle || pRectPatchInfo)) {
6042 /* TODO: Write a test for the return value, thus the FIXME */
6043 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6044 return WINED3DERR_INVALIDCALL;
6045 }
6046
6047 if(Handle) {
6048 i = PATCHMAP_HASHFUNC(Handle);
6049 found = FALSE;
6050 LIST_FOR_EACH(e, &This->patches[i]) {
6051 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6052 if(patch->Handle == Handle) {
6053 found = TRUE;
6054 break;
6055 }
6056 }
6057
6058 if(!found) {
6059 TRACE("Patch does not exist. Creating a new one\n");
6060 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6061 patch->Handle = Handle;
6062 list_add_head(&This->patches[i], &patch->entry);
6063 } else {
6064 TRACE("Found existing patch %p\n", patch);
6065 }
6066 } else {
6067 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6068 * attributes we have to tesselate, read back, and draw. This needs a patch
6069 * management structure instance. Create one.
6070 *
6071 * A possible improvement is to check if a vertex shader is used, and if not directly
6072 * draw the patch.
6073 */
6074 FIXME("Drawing an uncached patch. This is slow\n");
6075 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6076 }
6077
6078 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6079 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6080 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6081 HRESULT hr;
6082 TRACE("Tesselation density or patch info changed, retesselating\n");
6083
6084 if(pRectPatchInfo) {
6085 patch->RectPatchInfo = *pRectPatchInfo;
6086 }
6087 patch->numSegs[0] = pNumSegs[0];
6088 patch->numSegs[1] = pNumSegs[1];
6089 patch->numSegs[2] = pNumSegs[2];
6090 patch->numSegs[3] = pNumSegs[3];
6091
6092 hr = tesselate_rectpatch(This, patch);
6093 if(FAILED(hr)) {
6094 WARN("Patch tesselation failed\n");
6095
6096 /* Do not release the handle to store the params of the patch */
6097 if(!Handle) {
6098 HeapFree(GetProcessHeap(), 0, patch);
6099 }
6100 return hr;
6101 }
6102 }
6103
6104 This->currentPatch = patch;
6105 old_primitive_type = This->stateBlock->gl_primitive_type;
6106 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6107 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6108 This->stateBlock->gl_primitive_type = old_primitive_type;
6109 This->currentPatch = NULL;
6110
6111 /* Destroy uncached patches */
6112 if(!Handle) {
6113 HeapFree(GetProcessHeap(), 0, patch->mem);
6114 HeapFree(GetProcessHeap(), 0, patch);
6115 }
6116 return WINED3D_OK;
6117}
6118
6119static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6121 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6122 FIXME("(%p) : Stub\n", This);
6123 return WINED3D_OK;
6124}
6125
6126static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 int i;
6129 struct WineD3DRectPatch *patch;
6130 struct list *e;
6131 TRACE("(%p) Handle(%d)\n", This, Handle);
6132
6133 i = PATCHMAP_HASHFUNC(Handle);
6134 LIST_FOR_EACH(e, &This->patches[i]) {
6135 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6136 if(patch->Handle == Handle) {
6137 TRACE("Deleting patch %p\n", patch);
6138 list_remove(&patch->entry);
6139 HeapFree(GetProcessHeap(), 0, patch->mem);
6140 HeapFree(GetProcessHeap(), 0, patch);
6141 return WINED3D_OK;
6142 }
6143 }
6144
6145 /* TODO: Write a test for the return value */
6146 FIXME("Attempt to destroy nonexistent patch\n");
6147 return WINED3DERR_INVALIDCALL;
6148}
6149
6150static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6151 HRESULT hr;
6152 IWineD3DSwapChain *swapchain;
6153
6154 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6155 if (SUCCEEDED(hr)) {
6156 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6157 return swapchain;
6158 }
6159
6160 return NULL;
6161}
6162
6163static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6164 const WINED3DRECT *rect, const float color[4])
6165{
6166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6167 IWineD3DSwapChain *swapchain;
6168
6169 swapchain = get_swapchain(surface);
6170 if (swapchain) {
6171 GLenum buffer;
6172
6173 TRACE("Surface %p is onscreen\n", surface);
6174
6175 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6176 ENTER_GL();
6177 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6178 buffer = surface_get_gl_buffer(surface, swapchain);
6179 glDrawBuffer(buffer);
6180 checkGLcall("glDrawBuffer()");
6181 } else {
6182 TRACE("Surface %p is offscreen\n", surface);
6183
6184 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6185 ENTER_GL();
6186 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6187 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6188 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6189 checkGLcall("glFramebufferRenderbufferEXT");
6190 }
6191
6192 if (rect) {
6193 glEnable(GL_SCISSOR_TEST);
6194 if(!swapchain) {
6195 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6196 } else {
6197 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6198 rect->x2 - rect->x1, rect->y2 - rect->y1);
6199 }
6200 checkGLcall("glScissor");
6201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6202 } else {
6203 glDisable(GL_SCISSOR_TEST);
6204 }
6205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6206
6207 glDisable(GL_BLEND);
6208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6209
6210 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6212
6213 glClearColor(color[0], color[1], color[2], color[3]);
6214 glClear(GL_COLOR_BUFFER_BIT);
6215 checkGLcall("glClear");
6216
6217 if (This->activeContext->current_fbo) {
6218 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6219 } else {
6220 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6221 checkGLcall("glBindFramebuffer()");
6222 }
6223
6224 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6225 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6226 glDrawBuffer(GL_BACK);
6227 checkGLcall("glDrawBuffer()");
6228 }
6229
6230 LEAVE_GL();
6231}
6232
6233static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6234 unsigned int r, g, b, a;
6235 DWORD ret;
6236
6237 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6238 destfmt == WINED3DFMT_R8G8B8)
6239 return color;
6240
6241 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6242
6243 a = (color & 0xff000000) >> 24;
6244 r = (color & 0x00ff0000) >> 16;
6245 g = (color & 0x0000ff00) >> 8;
6246 b = (color & 0x000000ff) >> 0;
6247
6248 switch(destfmt)
6249 {
6250 case WINED3DFMT_R5G6B5:
6251 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6252 r = (r * 32) / 256;
6253 g = (g * 64) / 256;
6254 b = (b * 32) / 256;
6255 ret = r << 11;
6256 ret |= g << 5;
6257 ret |= b;
6258 TRACE("Returning %08x\n", ret);
6259 return ret;
6260
6261 case WINED3DFMT_X1R5G5B5:
6262 case WINED3DFMT_A1R5G5B5:
6263 a = (a * 2) / 256;
6264 r = (r * 32) / 256;
6265 g = (g * 32) / 256;
6266 b = (b * 32) / 256;
6267 ret = a << 15;
6268 ret |= r << 10;
6269 ret |= g << 5;
6270 ret |= b << 0;
6271 TRACE("Returning %08x\n", ret);
6272 return ret;
6273
6274 case WINED3DFMT_A8_UNORM:
6275 TRACE("Returning %08x\n", a);
6276 return a;
6277
6278 case WINED3DFMT_X4R4G4B4:
6279 case WINED3DFMT_A4R4G4B4:
6280 a = (a * 16) / 256;
6281 r = (r * 16) / 256;
6282 g = (g * 16) / 256;
6283 b = (b * 16) / 256;
6284 ret = a << 12;
6285 ret |= r << 8;
6286 ret |= g << 4;
6287 ret |= b << 0;
6288 TRACE("Returning %08x\n", ret);
6289 return ret;
6290
6291 case WINED3DFMT_R3G3B2:
6292 r = (r * 8) / 256;
6293 g = (g * 8) / 256;
6294 b = (b * 4) / 256;
6295 ret = r << 5;
6296 ret |= g << 2;
6297 ret |= b << 0;
6298 TRACE("Returning %08x\n", ret);
6299 return ret;
6300
6301 case WINED3DFMT_X8B8G8R8:
6302 case WINED3DFMT_R8G8B8A8_UNORM:
6303 ret = a << 24;
6304 ret |= b << 16;
6305 ret |= g << 8;
6306 ret |= r << 0;
6307 TRACE("Returning %08x\n", ret);
6308 return ret;
6309
6310 case WINED3DFMT_A2R10G10B10:
6311 a = (a * 4) / 256;
6312 r = (r * 1024) / 256;
6313 g = (g * 1024) / 256;
6314 b = (b * 1024) / 256;
6315 ret = a << 30;
6316 ret |= r << 20;
6317 ret |= g << 10;
6318 ret |= b << 0;
6319 TRACE("Returning %08x\n", ret);
6320 return ret;
6321
6322 case WINED3DFMT_R10G10B10A2_UNORM:
6323 a = (a * 4) / 256;
6324 r = (r * 1024) / 256;
6325 g = (g * 1024) / 256;
6326 b = (b * 1024) / 256;
6327 ret = a << 30;
6328 ret |= b << 20;
6329 ret |= g << 10;
6330 ret |= r << 0;
6331 TRACE("Returning %08x\n", ret);
6332 return ret;
6333
6334 default:
6335 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6336 return 0;
6337 }
6338}
6339
6340static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6342 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6343 WINEDDBLTFX BltFx;
6344 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6345
6346 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6347 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6348 return WINED3DERR_INVALIDCALL;
6349 }
6350
6351 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6352 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6353 color_fill_fbo(iface, pSurface, pRect, c);
6354 return WINED3D_OK;
6355 } else {
6356 /* Just forward this to the DirectDraw blitting engine */
6357 memset(&BltFx, 0, sizeof(BltFx));
6358 BltFx.dwSize = sizeof(BltFx);
6359 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6360 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6361 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6362 }
6363}
6364
6365static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6366 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6367{
6368 IWineD3DResource *resource;
6369 IWineD3DSurface *surface;
6370 HRESULT hr;
6371
6372 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6373 if (FAILED(hr))
6374 {
6375 ERR("Failed to get resource, hr %#x\n", hr);
6376 return;
6377 }
6378
6379 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6380 {
6381 FIXME("Only supported on surface resources\n");
6382 IWineD3DResource_Release(resource);
6383 return;
6384 }
6385
6386 surface = (IWineD3DSurface *)resource;
6387
6388 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6389 {
6390 color_fill_fbo(iface, surface, NULL, color);
6391 }
6392 else
6393 {
6394 WINEDDBLTFX BltFx;
6395 WINED3DCOLOR c;
6396
6397 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6398
6399 c = ((DWORD)(color[2] * 255.0));
6400 c |= ((DWORD)(color[1] * 255.0)) << 8;
6401 c |= ((DWORD)(color[0] * 255.0)) << 16;
6402 c |= ((DWORD)(color[3] * 255.0)) << 24;
6403
6404 /* Just forward this to the DirectDraw blitting engine */
6405 memset(&BltFx, 0, sizeof(BltFx));
6406 BltFx.dwSize = sizeof(BltFx);
6407 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6408 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6409 if (FAILED(hr))
6410 {
6411 ERR("Blt failed, hr %#x\n", hr);
6412 }
6413 }
6414
6415 IWineD3DResource_Release(resource);
6416}
6417
6418/* rendertarget and depth stencil functions */
6419static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6421
6422 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6423 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6424 return WINED3DERR_INVALIDCALL;
6425 }
6426
6427 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6428 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6429 /* Note inc ref on returned surface */
6430 if(*ppRenderTarget != NULL)
6431 IWineD3DSurface_AddRef(*ppRenderTarget);
6432 return WINED3D_OK;
6433}
6434
6435static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6438 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6439 IWineD3DSwapChainImpl *Swapchain;
6440 HRESULT hr;
6441
6442 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6443
6444 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6445 if(hr != WINED3D_OK) {
6446 ERR("Can't get the swapchain\n");
6447 return hr;
6448 }
6449
6450 /* Make sure to release the swapchain */
6451 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6452
6453 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6454 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6455 return WINED3DERR_INVALIDCALL;
6456 }
6457 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6458 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6459 return WINED3DERR_INVALIDCALL;
6460 }
6461
6462 if(Swapchain->frontBuffer != Front) {
6463 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6464
6465 if(Swapchain->frontBuffer)
6466 {
6467 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6468 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6469 }
6470 Swapchain->frontBuffer = Front;
6471
6472 if(Swapchain->frontBuffer) {
6473 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6474 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6475 }
6476 }
6477
6478 if(Back && !Swapchain->backBuffer) {
6479 /* We need memory for the back buffer array - only one back buffer this way */
6480 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6481 if(!Swapchain->backBuffer) {
6482 ERR("Out of memory\n");
6483 return E_OUTOFMEMORY;
6484 }
6485 }
6486
6487 if(Swapchain->backBuffer[0] != Back) {
6488 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6489
6490 /* What to do about the context here in the case of multithreading? Not sure.
6491 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6492 */
6493 ENTER_GL();
6494 if(!Swapchain->backBuffer[0]) {
6495 /* GL was told to draw to the front buffer at creation,
6496 * undo that
6497 */
6498 glDrawBuffer(GL_BACK);
6499 checkGLcall("glDrawBuffer(GL_BACK)");
6500 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6501 Swapchain->presentParms.BackBufferCount = 1;
6502 } else if (!Back) {
6503 /* That makes problems - disable for now */
6504 /* glDrawBuffer(GL_FRONT); */
6505 checkGLcall("glDrawBuffer(GL_FRONT)");
6506 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6507 Swapchain->presentParms.BackBufferCount = 0;
6508 }
6509 LEAVE_GL();
6510
6511 if(Swapchain->backBuffer[0])
6512 {
6513 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6514 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6515 }
6516 Swapchain->backBuffer[0] = Back;
6517
6518 if(Swapchain->backBuffer[0]) {
6519 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6520 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6521 } else {
6522 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6523 Swapchain->backBuffer = NULL;
6524 }
6525
6526 }
6527
6528 return WINED3D_OK;
6529}
6530
6531static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 *ppZStencilSurface = This->stencilBufferTarget;
6534 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6535
6536 if(*ppZStencilSurface != NULL) {
6537 /* Note inc ref on returned surface */
6538 IWineD3DSurface_AddRef(*ppZStencilSurface);
6539 return WINED3D_OK;
6540 } else {
6541 return WINED3DERR_NOTFOUND;
6542 }
6543}
6544
6545void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6546 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6547{
6548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6549 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6550 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6551 GLenum gl_filter;
6552 POINT offset = {0, 0};
6553
6554 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6555 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6556 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6557 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6558
6559 switch (filter) {
6560 case WINED3DTEXF_LINEAR:
6561 gl_filter = GL_LINEAR;
6562 break;
6563
6564 default:
6565 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6566 case WINED3DTEXF_NONE:
6567 case WINED3DTEXF_POINT:
6568 gl_filter = GL_NEAREST;
6569 break;
6570 }
6571
6572 /* Attach src surface to src fbo */
6573 src_swapchain = get_swapchain(src_surface);
6574 if (src_swapchain) {
6575 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6576
6577 TRACE("Source surface %p is onscreen\n", src_surface);
6578 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6579 /* Make sure the drawable is up to date. In the offscreen case
6580 * attach_surface_fbo() implicitly takes care of this. */
6581 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6582
6583 if(buffer == GL_FRONT) {
6584 RECT windowsize;
6585 UINT h;
6586 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6587 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6588 h = windowsize.bottom - windowsize.top;
6589 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6590 src_rect->y1 = offset.y + h - src_rect->y1;
6591 src_rect->y2 = offset.y + h - src_rect->y2;
6592 } else {
6593 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6594 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6595 }
6596
6597 ENTER_GL();
6598 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6599 glReadBuffer(buffer);
6600 checkGLcall("glReadBuffer()");
6601 } else {
6602 TRACE("Source surface %p is offscreen\n", src_surface);
6603 ENTER_GL();
6604 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6605 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6606 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6607 checkGLcall("glReadBuffer()");
6608 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6609 checkGLcall("glFramebufferRenderbufferEXT");
6610 }
6611 LEAVE_GL();
6612
6613 /* Attach dst surface to dst fbo */
6614 dst_swapchain = get_swapchain(dst_surface);
6615 if (dst_swapchain) {
6616 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6617
6618 TRACE("Destination surface %p is onscreen\n", dst_surface);
6619 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6620 /* Make sure the drawable is up to date. In the offscreen case
6621 * attach_surface_fbo() implicitly takes care of this. */
6622 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6623
6624 if(buffer == GL_FRONT) {
6625 RECT windowsize;
6626 UINT h;
6627 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6628 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6629 h = windowsize.bottom - windowsize.top;
6630 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6631 dst_rect->y1 = offset.y + h - dst_rect->y1;
6632 dst_rect->y2 = offset.y + h - dst_rect->y2;
6633 } else {
6634 /* Screen coords = window coords, surface height = window height */
6635 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6636 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6637 }
6638
6639 ENTER_GL();
6640 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6641 glDrawBuffer(buffer);
6642 checkGLcall("glDrawBuffer()");
6643 } else {
6644 TRACE("Destination surface %p is offscreen\n", dst_surface);
6645
6646 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6647 if(!src_swapchain) {
6648 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6649 }
6650
6651 ENTER_GL();
6652 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6653 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6654 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6655 checkGLcall("glDrawBuffer()");
6656 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6657 checkGLcall("glFramebufferRenderbufferEXT");
6658 }
6659 glDisable(GL_SCISSOR_TEST);
6660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6661
6662 if (flip) {
6663 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6664 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6665 checkGLcall("glBlitFramebuffer()");
6666 } else {
6667 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6668 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6669 checkGLcall("glBlitFramebuffer()");
6670 }
6671
6672 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6673
6674 if (This->activeContext->current_fbo) {
6675 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6676 } else {
6677 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6678 checkGLcall("glBindFramebuffer()");
6679 }
6680
6681 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6682 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6683 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6684 glDrawBuffer(GL_BACK);
6685 checkGLcall("glDrawBuffer()");
6686 }
6687 LEAVE_GL();
6688}
6689
6690static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6692 WINED3DVIEWPORT viewport;
6693
6694 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6695
6696 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6697 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6698 This, RenderTargetIndex, GL_LIMITS(buffers));
6699 return WINED3DERR_INVALIDCALL;
6700 }
6701
6702 /* MSDN says that null disables the render target
6703 but a device must always be associated with a render target
6704 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6705 */
6706 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6707 FIXME("Trying to set render target 0 to NULL\n");
6708 return WINED3DERR_INVALIDCALL;
6709 }
6710 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6711 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);
6712 return WINED3DERR_INVALIDCALL;
6713 }
6714
6715 /* If we are trying to set what we already have, don't bother */
6716 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6717 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6718 return WINED3D_OK;
6719 }
6720 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6721 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6722 This->render_targets[RenderTargetIndex] = pRenderTarget;
6723
6724 /* Render target 0 is special */
6725 if(RenderTargetIndex == 0) {
6726 /* Finally, reset the viewport as the MSDN states. */
6727 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6728 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6729 viewport.X = 0;
6730 viewport.Y = 0;
6731 viewport.MaxZ = 1.0f;
6732 viewport.MinZ = 0.0f;
6733 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6734 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6735 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6736 */
6737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6738 }
6739 return WINED3D_OK;
6740}
6741
6742static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6744 HRESULT hr = WINED3D_OK;
6745 IWineD3DSurface *tmp;
6746
6747 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6748
6749 if (pNewZStencil == This->stencilBufferTarget) {
6750 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6751 } else {
6752 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6753 * depending on the renter target implementation being used.
6754 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6755 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6756 * stencil buffer and incur an extra memory overhead
6757 ******************************************************/
6758
6759 if (This->stencilBufferTarget) {
6760 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6761 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6762 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6763 } else {
6764 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6765 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6766 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6767 }
6768 }
6769
6770 tmp = This->stencilBufferTarget;
6771 This->stencilBufferTarget = pNewZStencil;
6772 /* should we be calling the parent or the wined3d surface? */
6773 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6774 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6775 hr = WINED3D_OK;
6776
6777 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6778 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6782 }
6783 }
6784
6785 return hr;
6786}
6787
6788static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6789 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6791 /* TODO: the use of Impl is deprecated. */
6792 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6793 WINED3DLOCKED_RECT lockedRect;
6794
6795 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6796
6797 /* some basic validation checks */
6798 if(This->cursorTexture) {
6799 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6800 ENTER_GL();
6801 glDeleteTextures(1, &This->cursorTexture);
6802 LEAVE_GL();
6803 This->cursorTexture = 0;
6804 }
6805
6806 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6807 This->haveHardwareCursor = TRUE;
6808 else
6809 This->haveHardwareCursor = FALSE;
6810
6811 if(pCursorBitmap) {
6812 WINED3DLOCKED_RECT rect;
6813
6814 /* MSDN: Cursor must be A8R8G8B8 */
6815 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6816 {
6817 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6818 return WINED3DERR_INVALIDCALL;
6819 }
6820
6821 /* MSDN: Cursor must be smaller than the display mode */
6822 if(pSur->currentDesc.Width > This->ddraw_width ||
6823 pSur->currentDesc.Height > This->ddraw_height) {
6824 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);
6825 return WINED3DERR_INVALIDCALL;
6826 }
6827
6828 if (!This->haveHardwareCursor) {
6829 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6830
6831 /* Do not store the surface's pointer because the application may
6832 * release it after setting the cursor image. Windows doesn't
6833 * addref the set surface, so we can't do this either without
6834 * creating circular refcount dependencies. Copy out the gl texture
6835 * instead.
6836 */
6837 This->cursorWidth = pSur->currentDesc.Width;
6838 This->cursorHeight = pSur->currentDesc.Height;
6839 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6840 {
6841 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6842 char *mem, *bits = rect.pBits;
6843 GLint intfmt = glDesc->glInternal;
6844 GLint format = glDesc->glFormat;
6845 GLint type = glDesc->glType;
6846 INT height = This->cursorHeight;
6847 INT width = This->cursorWidth;
6848 INT bpp = glDesc->byte_count;
6849 INT i, sampler;
6850
6851 /* Reformat the texture memory (pitch and width can be
6852 * different) */
6853 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6854 for(i = 0; i < height; i++)
6855 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6856 IWineD3DSurface_UnlockRect(pCursorBitmap);
6857 ENTER_GL();
6858
6859 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6860 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6861 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6862 }
6863
6864 /* Make sure that a proper texture unit is selected */
6865 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6866 checkGLcall("glActiveTextureARB");
6867 sampler = This->rev_tex_unit_map[0];
6868 if (sampler != -1) {
6869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6870 }
6871 /* Create a new cursor texture */
6872 glGenTextures(1, &This->cursorTexture);
6873 checkGLcall("glGenTextures");
6874 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6875 checkGLcall("glBindTexture");
6876 /* Copy the bitmap memory into the cursor texture */
6877 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6878 HeapFree(GetProcessHeap(), 0, mem);
6879 checkGLcall("glTexImage2D");
6880
6881 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6882 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6883 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6884 }
6885
6886 LEAVE_GL();
6887 }
6888 else
6889 {
6890 FIXME("A cursor texture was not returned.\n");
6891 This->cursorTexture = 0;
6892 }
6893 }
6894 else
6895 {
6896 /* Draw a hardware cursor */
6897 ICONINFO cursorInfo;
6898 HCURSOR cursor;
6899 /* Create and clear maskBits because it is not needed for
6900 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6901 * chunks. */
6902 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6903 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6904 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6905 WINED3DLOCK_NO_DIRTY_UPDATE |
6906 WINED3DLOCK_READONLY
6907 );
6908 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6909 pSur->currentDesc.Height);
6910
6911 cursorInfo.fIcon = FALSE;
6912 cursorInfo.xHotspot = XHotSpot;
6913 cursorInfo.yHotspot = YHotSpot;
6914 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6915 pSur->currentDesc.Height, 1,
6916 1, &maskBits);
6917 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6918 pSur->currentDesc.Height, 1,
6919 32, lockedRect.pBits);
6920 IWineD3DSurface_UnlockRect(pCursorBitmap);
6921 /* Create our cursor and clean up. */
6922 cursor = CreateIconIndirect(&cursorInfo);
6923 SetCursor(cursor);
6924 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6925 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6926 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6927 This->hardwareCursor = cursor;
6928 HeapFree(GetProcessHeap(), 0, maskBits);
6929 }
6930 }
6931
6932 This->xHotSpot = XHotSpot;
6933 This->yHotSpot = YHotSpot;
6934 return WINED3D_OK;
6935}
6936
6937static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6939 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6940
6941 This->xScreenSpace = XScreenSpace;
6942 This->yScreenSpace = YScreenSpace;
6943
6944 return;
6945
6946}
6947
6948static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6950 BOOL oldVisible = This->bCursorVisible;
6951 POINT pt;
6952
6953 TRACE("(%p) : visible(%d)\n", This, bShow);
6954
6955 /*
6956 * When ShowCursor is first called it should make the cursor appear at the OS's last
6957 * known cursor position. Because of this, some applications just repetitively call
6958 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6959 */
6960 GetCursorPos(&pt);
6961 This->xScreenSpace = pt.x;
6962 This->yScreenSpace = pt.y;
6963
6964 if (This->haveHardwareCursor) {
6965 This->bCursorVisible = bShow;
6966 if (bShow)
6967 SetCursor(This->hardwareCursor);
6968 else
6969 SetCursor(NULL);
6970 }
6971 else
6972 {
6973 if (This->cursorTexture)
6974 This->bCursorVisible = bShow;
6975 }
6976
6977 return oldVisible;
6978}
6979
6980static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6982 IWineD3DResourceImpl *resource;
6983 TRACE("(%p) : state (%u)\n", This, This->state);
6984
6985 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6986 switch (This->state) {
6987 case WINED3D_OK:
6988 return WINED3D_OK;
6989 case WINED3DERR_DEVICELOST:
6990 {
6991 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6992 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6993 return WINED3DERR_DEVICENOTRESET;
6994 }
6995 return WINED3DERR_DEVICELOST;
6996 }
6997 case WINED3DERR_DRIVERINTERNALERROR:
6998 return WINED3DERR_DRIVERINTERNALERROR;
6999 }
7000
7001 /* Unknown state */
7002 return WINED3DERR_DRIVERINTERNALERROR;
7003}
7004
7005
7006static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7008 /** FIXME: Resource tracking needs to be done,
7009 * The closes we can do to this is set the priorities of all managed textures low
7010 * and then reset them.
7011 ***********************************************************/
7012 FIXME("(%p) : stub\n", This);
7013 return WINED3D_OK;
7014}
7015
7016static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7017{
7018 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7019
7020 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7021 if(surface->Flags & SFLAG_DIBSECTION) {
7022 /* Release the DC */
7023 SelectObject(surface->hDC, surface->dib.holdbitmap);
7024 DeleteDC(surface->hDC);
7025 /* Release the DIB section */
7026 DeleteObject(surface->dib.DIBsection);
7027 surface->dib.bitmap_data = NULL;
7028 surface->resource.allocatedMemory = NULL;
7029 surface->Flags &= ~SFLAG_DIBSECTION;
7030 }
7031 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7032 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7033 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7034 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7035 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7036 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7037 } else {
7038 surface->pow2Width = surface->pow2Height = 1;
7039 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7040 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7041 }
7042 surface->glRect.left = 0;
7043 surface->glRect.top = 0;
7044 surface->glRect.right = surface->pow2Width;
7045 surface->glRect.bottom = surface->pow2Height;
7046
7047 if(surface->glDescription.textureName) {
7048 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7049 ENTER_GL();
7050 glDeleteTextures(1, &surface->glDescription.textureName);
7051 LEAVE_GL();
7052 surface->glDescription.textureName = 0;
7053 surface->Flags &= ~SFLAG_CLIENT;
7054 }
7055 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7056 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7057 surface->Flags |= SFLAG_NONPOW2;
7058 } else {
7059 surface->Flags &= ~SFLAG_NONPOW2;
7060 }
7061 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7062 surface->resource.allocatedMemory = NULL;
7063 surface->resource.heapMemory = NULL;
7064 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7065 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7066 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7067 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7068 } else {
7069 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7070 }
7071}
7072
7073static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7074 TRACE("Unloading resource %p\n", resource);
7075 IWineD3DResource_UnLoad(resource);
7076 IWineD3DResource_Release(resource);
7077 return S_OK;
7078}
7079
7080static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7081{
7082 UINT i, count;
7083 WINED3DDISPLAYMODE m;
7084 HRESULT hr;
7085
7086 /* All Windowed modes are supported, as is leaving the current mode */
7087 if(pp->Windowed) return TRUE;
7088 if(!pp->BackBufferWidth) return TRUE;
7089 if(!pp->BackBufferHeight) return TRUE;
7090
7091 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7092 for(i = 0; i < count; i++) {
7093 memset(&m, 0, sizeof(m));
7094 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7095 if(FAILED(hr)) {
7096 ERR("EnumAdapterModes failed\n");
7097 }
7098 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7099 /* Mode found, it is supported */
7100 return TRUE;
7101 }
7102 }
7103 /* Mode not found -> not supported */
7104 return FALSE;
7105}
7106
7107void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7109 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7110 UINT i;
7111 IWineD3DBaseShaderImpl *shader;
7112
7113 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7114 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7115 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7116 }
7117
7118 ENTER_GL();
7119 if(This->depth_blt_texture) {
7120 glDeleteTextures(1, &This->depth_blt_texture);
7121 This->depth_blt_texture = 0;
7122 }
7123 if (This->depth_blt_rb) {
7124 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7125 This->depth_blt_rb = 0;
7126 This->depth_blt_rb_w = 0;
7127 This->depth_blt_rb_h = 0;
7128 }
7129 LEAVE_GL();
7130
7131 This->blitter->free_private(iface);
7132 This->frag_pipe->free_private(iface);
7133 This->shader_backend->shader_free_private(iface);
7134
7135 ENTER_GL();
7136 for (i = 0; i < GL_LIMITS(textures); i++) {
7137 /* Textures are recreated below */
7138 glDeleteTextures(1, &This->dummyTextureName[i]);
7139 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7140 This->dummyTextureName[i] = 0;
7141 }
7142 LEAVE_GL();
7143
7144 while(This->numContexts) {
7145 DestroyContext(This, This->contexts[0]);
7146 }
7147 This->activeContext = NULL;
7148 HeapFree(GetProcessHeap(), 0, swapchain->context);
7149 swapchain->context = NULL;
7150 swapchain->num_contexts = 0;
7151}
7152
7153HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7155 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7156 HRESULT hr;
7157 IWineD3DSurfaceImpl *target;
7158
7159 /* Recreate the primary swapchain's context */
7160 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7161 if(swapchain->backBuffer) {
7162 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7163 } else {
7164 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7165 }
7166 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7167 &swapchain->presentParms);
7168 swapchain->num_contexts = 1;
7169 This->activeContext = swapchain->context[0];
7170
7171 create_dummy_textures(This);
7172
7173 hr = This->shader_backend->shader_alloc_private(iface);
7174 if(FAILED(hr)) {
7175 ERR("Failed to recreate shader private data\n");
7176 goto err_out;
7177 }
7178 hr = This->frag_pipe->alloc_private(iface);
7179 if(FAILED(hr)) {
7180 TRACE("Fragment pipeline private data couldn't be allocated\n");
7181 goto err_out;
7182 }
7183 hr = This->blitter->alloc_private(iface);
7184 if(FAILED(hr)) {
7185 TRACE("Blitter private data couldn't be allocated\n");
7186 goto err_out;
7187 }
7188
7189 return WINED3D_OK;
7190
7191err_out:
7192 This->blitter->free_private(iface);
7193 This->frag_pipe->free_private(iface);
7194 This->shader_backend->shader_free_private(iface);
7195 return hr;
7196}
7197
7198static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7200 IWineD3DSwapChainImpl *swapchain;
7201 HRESULT hr;
7202 BOOL DisplayModeChanged = FALSE;
7203 WINED3DDISPLAYMODE mode;
7204 TRACE("(%p)\n", This);
7205
7206 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7207 if(FAILED(hr)) {
7208 ERR("Failed to get the first implicit swapchain\n");
7209 return hr;
7210 }
7211
7212 if(!is_display_mode_supported(This, pPresentationParameters)) {
7213 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7214 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7215 pPresentationParameters->BackBufferHeight);
7216 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7217 return WINED3DERR_INVALIDCALL;
7218 }
7219
7220 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7221 * on an existing gl context, so there's no real need for recreation.
7222 *
7223 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7224 *
7225 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7226 */
7227 TRACE("New params:\n");
7228 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7229 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7230 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7231 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7232 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7233 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7234 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7235 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7236 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7237 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7238 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7239 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7240 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7241
7242 /* No special treatment of these parameters. Just store them */
7243 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7244 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7245 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7246 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7247
7248 /* What to do about these? */
7249 if(pPresentationParameters->BackBufferCount != 0 &&
7250 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7251 ERR("Cannot change the back buffer count yet\n");
7252 }
7253 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7254 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7255 ERR("Cannot change the back buffer format yet\n");
7256 }
7257 if(pPresentationParameters->hDeviceWindow != NULL &&
7258 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7259 ERR("Cannot change the device window yet\n");
7260 }
7261 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7262 HRESULT hrc;
7263
7264 TRACE("Creating the depth stencil buffer\n");
7265
7266 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7267 This->parent,
7268 pPresentationParameters->BackBufferWidth,
7269 pPresentationParameters->BackBufferHeight,
7270 pPresentationParameters->AutoDepthStencilFormat,
7271 pPresentationParameters->MultiSampleType,
7272 pPresentationParameters->MultiSampleQuality,
7273 FALSE,
7274 &This->auto_depth_stencil_buffer);
7275
7276 if (FAILED(hrc)) {
7277 ERR("Failed to create the depth stencil buffer\n");
7278 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7279 return WINED3DERR_INVALIDCALL;
7280 }
7281 }
7282
7283 /* Reset the depth stencil */
7284 if (pPresentationParameters->EnableAutoDepthStencil)
7285 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7286 else
7287 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7288
7289 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7290
7291 if(pPresentationParameters->Windowed) {
7292 mode.Width = swapchain->orig_width;
7293 mode.Height = swapchain->orig_height;
7294 mode.RefreshRate = 0;
7295 mode.Format = swapchain->presentParms.BackBufferFormat;
7296 } else {
7297 mode.Width = pPresentationParameters->BackBufferWidth;
7298 mode.Height = pPresentationParameters->BackBufferHeight;
7299 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7300 mode.Format = swapchain->presentParms.BackBufferFormat;
7301 }
7302
7303 /* Should Width == 800 && Height == 0 set 800x600? */
7304 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7305 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7306 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7307 {
7308 UINT i;
7309
7310 if(!pPresentationParameters->Windowed) {
7311 DisplayModeChanged = TRUE;
7312 }
7313 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7314 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7315
7316 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7317 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7318 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7319 }
7320 if(This->auto_depth_stencil_buffer) {
7321 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7322 }
7323 }
7324
7325 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7326 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7327 DisplayModeChanged) {
7328
7329 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7330
7331 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7332 if(swapchain->presentParms.Windowed) {
7333 /* switch from windowed to fs */
7334 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7335 pPresentationParameters->BackBufferWidth,
7336 pPresentationParameters->BackBufferHeight);
7337 } else {
7338 /* Fullscreen -> fullscreen mode change */
7339 MoveWindow(swapchain->win_handle, 0, 0,
7340 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7341 TRUE);
7342 }
7343 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7344 /* Fullscreen -> windowed switch */
7345 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7346 }
7347 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7348 } else if(!pPresentationParameters->Windowed) {
7349 DWORD style = This->style, exStyle = This->exStyle;
7350 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7351 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7352 * Reset to clear up their mess. Guild Wars also loses the device during that.
7353 */
7354 This->style = 0;
7355 This->exStyle = 0;
7356 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7357 pPresentationParameters->BackBufferWidth,
7358 pPresentationParameters->BackBufferHeight);
7359 This->style = style;
7360 This->exStyle = exStyle;
7361 }
7362
7363 TRACE("Resetting stateblock\n");
7364 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7365 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7366
7367 /* Note: No parent needed for initial internal stateblock */
7368 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7369 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7370 else TRACE("Created stateblock %p\n", This->stateBlock);
7371 This->updateStateBlock = This->stateBlock;
7372 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7373
7374 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7375 if(FAILED(hr)) {
7376 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7377 }
7378
7379 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7380 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7381
7382 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7383 * first use
7384 */
7385 return hr;
7386}
7387
7388static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7390 /** FIXME: always true at the moment **/
7391 if(!bEnableDialogs) {
7392 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7393 }
7394 return WINED3D_OK;
7395}
7396
7397
7398static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7400 TRACE("(%p) : pParameters %p\n", This, pParameters);
7401
7402 *pParameters = This->createParms;
7403 return WINED3D_OK;
7404}
7405
7406static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7407 IWineD3DSwapChain *swapchain;
7408
7409 TRACE("Relaying to swapchain\n");
7410
7411 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7412 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7413 IWineD3DSwapChain_Release(swapchain);
7414 }
7415 return;
7416}
7417
7418static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7419 IWineD3DSwapChain *swapchain;
7420
7421 TRACE("Relaying to swapchain\n");
7422
7423 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7424 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7425 IWineD3DSwapChain_Release(swapchain);
7426 }
7427 return;
7428}
7429
7430
7431/** ********************************************************
7432* Notification functions
7433** ********************************************************/
7434/** This function must be called in the release of a resource when ref == 0,
7435* the contents of resource must still be correct,
7436* any handles to other resource held by the caller must be closed
7437* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7438 *****************************************************/
7439void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7440{
7441 TRACE("(%p) : Adding resource %p\n", This, resource);
7442
7443 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7444}
7445
7446static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7447{
7448 TRACE("(%p) : Removing resource %p\n", This, resource);
7449
7450 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7451}
7452
7453void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7454{
7455 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7456 int counter;
7457
7458 TRACE("(%p) : resource %p\n", This, resource);
7459
7460 context_resource_released((IWineD3DDevice *)This, resource, type);
7461
7462 switch (type) {
7463 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7464 case WINED3DRTYPE_SURFACE: {
7465 unsigned int i;
7466
7467 /* Cleanup any FBO attachments if d3d is enabled */
7468 if(This->d3d_initialized) {
7469 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7470 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7471
7472 TRACE("Last active render target destroyed\n");
7473 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7474 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7475 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7476 * and the lastActiveRenderTarget member shouldn't matter
7477 */
7478 if(swapchain) {
7479 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7480 TRACE("Activating primary back buffer\n");
7481 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7482 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7483 /* Single buffering environment */
7484 TRACE("Activating primary front buffer\n");
7485 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7486 } else {
7487 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7488 /* Implicit render target destroyed, that means the device is being destroyed
7489 * whatever we set here, it shouldn't matter
7490 */
7491 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7492 }
7493 } else {
7494 /* May happen during ddraw uninitialization */
7495 TRACE("Render target set, but swapchain does not exist!\n");
7496 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7497 }
7498 }
7499
7500 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7501 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7502 This->render_targets[i] = NULL;
7503 }
7504 }
7505 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7506 This->stencilBufferTarget = NULL;
7507 }
7508 }
7509
7510 break;
7511 }
7512 case WINED3DRTYPE_TEXTURE:
7513 case WINED3DRTYPE_CUBETEXTURE:
7514 case WINED3DRTYPE_VOLUMETEXTURE:
7515 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7516 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7517 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7518 This->stateBlock->textures[counter] = NULL;
7519 }
7520 if (This->updateStateBlock != This->stateBlock ){
7521 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7522 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7523 This->updateStateBlock->textures[counter] = NULL;
7524 }
7525 }
7526 }
7527 break;
7528 case WINED3DRTYPE_VOLUME:
7529 /* TODO: nothing really? */
7530 break;
7531 case WINED3DRTYPE_BUFFER:
7532 {
7533 int streamNumber;
7534 TRACE("Cleaning up stream pointers\n");
7535
7536 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7537 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7538 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7539 */
7540 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7541 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7542 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7543 This->updateStateBlock->streamSource[streamNumber] = 0;
7544 /* Set changed flag? */
7545 }
7546 }
7547 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) */
7548 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7549 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7550 This->stateBlock->streamSource[streamNumber] = 0;
7551 }
7552 }
7553 }
7554
7555 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7556 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7557 This->updateStateBlock->pIndexData = NULL;
7558 }
7559 }
7560 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7561 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7562 This->stateBlock->pIndexData = NULL;
7563 }
7564 }
7565 }
7566 break;
7567
7568 default:
7569 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7570 break;
7571 }
7572
7573
7574 /* Remove the resource from the resourceStore */
7575 device_resource_remove(This, resource);
7576
7577 TRACE("Resource released\n");
7578
7579}
7580
7581static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7583 IWineD3DResourceImpl *resource, *cursor;
7584 HRESULT ret;
7585 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7586
7587 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7588 TRACE("enumerating resource %p\n", resource);
7589 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7590 ret = pCallback((IWineD3DResource *) resource, pData);
7591 if(ret == S_FALSE) {
7592 TRACE("Canceling enumeration\n");
7593 break;
7594 }
7595 }
7596 return WINED3D_OK;
7597}
7598
7599/**********************************************************
7600 * IWineD3DDevice VTbl follows
7601 **********************************************************/
7602
7603const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7604{
7605 /*** IUnknown methods ***/
7606 IWineD3DDeviceImpl_QueryInterface,
7607 IWineD3DDeviceImpl_AddRef,
7608 IWineD3DDeviceImpl_Release,
7609 /*** IWineD3DDevice methods ***/
7610 IWineD3DDeviceImpl_GetParent,
7611 /*** Creation methods**/
7612 IWineD3DDeviceImpl_CreateBuffer,
7613 IWineD3DDeviceImpl_CreateVertexBuffer,
7614 IWineD3DDeviceImpl_CreateIndexBuffer,
7615 IWineD3DDeviceImpl_CreateStateBlock,
7616 IWineD3DDeviceImpl_CreateSurface,
7617 IWineD3DDeviceImpl_CreateRendertargetView,
7618 IWineD3DDeviceImpl_CreateTexture,
7619 IWineD3DDeviceImpl_CreateVolumeTexture,
7620 IWineD3DDeviceImpl_CreateVolume,
7621 IWineD3DDeviceImpl_CreateCubeTexture,
7622 IWineD3DDeviceImpl_CreateQuery,
7623 IWineD3DDeviceImpl_CreateSwapChain,
7624 IWineD3DDeviceImpl_CreateVertexDeclaration,
7625 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7626 IWineD3DDeviceImpl_CreateVertexShader,
7627 IWineD3DDeviceImpl_CreatePixelShader,
7628 IWineD3DDeviceImpl_CreatePalette,
7629 /*** Odd functions **/
7630 IWineD3DDeviceImpl_Init3D,
7631 IWineD3DDeviceImpl_InitGDI,
7632 IWineD3DDeviceImpl_Uninit3D,
7633 IWineD3DDeviceImpl_UninitGDI,
7634 IWineD3DDeviceImpl_SetMultithreaded,
7635 IWineD3DDeviceImpl_EvictManagedResources,
7636 IWineD3DDeviceImpl_GetAvailableTextureMem,
7637 IWineD3DDeviceImpl_GetBackBuffer,
7638 IWineD3DDeviceImpl_GetCreationParameters,
7639 IWineD3DDeviceImpl_GetDeviceCaps,
7640 IWineD3DDeviceImpl_GetDirect3D,
7641 IWineD3DDeviceImpl_GetDisplayMode,
7642 IWineD3DDeviceImpl_SetDisplayMode,
7643 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7644 IWineD3DDeviceImpl_GetRasterStatus,
7645 IWineD3DDeviceImpl_GetSwapChain,
7646 IWineD3DDeviceImpl_Reset,
7647 IWineD3DDeviceImpl_SetDialogBoxMode,
7648 IWineD3DDeviceImpl_SetCursorProperties,
7649 IWineD3DDeviceImpl_SetCursorPosition,
7650 IWineD3DDeviceImpl_ShowCursor,
7651 IWineD3DDeviceImpl_TestCooperativeLevel,
7652 /*** Getters and setters **/
7653 IWineD3DDeviceImpl_SetClipPlane,
7654 IWineD3DDeviceImpl_GetClipPlane,
7655 IWineD3DDeviceImpl_SetClipStatus,
7656 IWineD3DDeviceImpl_GetClipStatus,
7657 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7658 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7659 IWineD3DDeviceImpl_SetDepthStencilSurface,
7660 IWineD3DDeviceImpl_GetDepthStencilSurface,
7661 IWineD3DDeviceImpl_SetGammaRamp,
7662 IWineD3DDeviceImpl_GetGammaRamp,
7663 IWineD3DDeviceImpl_SetIndices,
7664 IWineD3DDeviceImpl_GetIndices,
7665 IWineD3DDeviceImpl_SetBaseVertexIndex,
7666 IWineD3DDeviceImpl_GetBaseVertexIndex,
7667 IWineD3DDeviceImpl_SetLight,
7668 IWineD3DDeviceImpl_GetLight,
7669 IWineD3DDeviceImpl_SetLightEnable,
7670 IWineD3DDeviceImpl_GetLightEnable,
7671 IWineD3DDeviceImpl_SetMaterial,
7672 IWineD3DDeviceImpl_GetMaterial,
7673 IWineD3DDeviceImpl_SetNPatchMode,
7674 IWineD3DDeviceImpl_GetNPatchMode,
7675 IWineD3DDeviceImpl_SetPaletteEntries,
7676 IWineD3DDeviceImpl_GetPaletteEntries,
7677 IWineD3DDeviceImpl_SetPixelShader,
7678 IWineD3DDeviceImpl_GetPixelShader,
7679 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7680 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7681 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7682 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7683 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7684 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7685 IWineD3DDeviceImpl_SetRenderState,
7686 IWineD3DDeviceImpl_GetRenderState,
7687 IWineD3DDeviceImpl_SetRenderTarget,
7688 IWineD3DDeviceImpl_GetRenderTarget,
7689 IWineD3DDeviceImpl_SetFrontBackBuffers,
7690 IWineD3DDeviceImpl_SetSamplerState,
7691 IWineD3DDeviceImpl_GetSamplerState,
7692 IWineD3DDeviceImpl_SetScissorRect,
7693 IWineD3DDeviceImpl_GetScissorRect,
7694 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7695 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7696 IWineD3DDeviceImpl_SetStreamSource,
7697 IWineD3DDeviceImpl_GetStreamSource,
7698 IWineD3DDeviceImpl_SetStreamSourceFreq,
7699 IWineD3DDeviceImpl_GetStreamSourceFreq,
7700 IWineD3DDeviceImpl_SetTexture,
7701 IWineD3DDeviceImpl_GetTexture,
7702 IWineD3DDeviceImpl_SetTextureStageState,
7703 IWineD3DDeviceImpl_GetTextureStageState,
7704 IWineD3DDeviceImpl_SetTransform,
7705 IWineD3DDeviceImpl_GetTransform,
7706 IWineD3DDeviceImpl_SetVertexDeclaration,
7707 IWineD3DDeviceImpl_GetVertexDeclaration,
7708 IWineD3DDeviceImpl_SetVertexShader,
7709 IWineD3DDeviceImpl_GetVertexShader,
7710 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7711 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7712 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7713 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7714 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7715 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7716 IWineD3DDeviceImpl_SetViewport,
7717 IWineD3DDeviceImpl_GetViewport,
7718 IWineD3DDeviceImpl_MultiplyTransform,
7719 IWineD3DDeviceImpl_ValidateDevice,
7720 IWineD3DDeviceImpl_ProcessVertices,
7721 /*** State block ***/
7722 IWineD3DDeviceImpl_BeginStateBlock,
7723 IWineD3DDeviceImpl_EndStateBlock,
7724 /*** Scene management ***/
7725 IWineD3DDeviceImpl_BeginScene,
7726 IWineD3DDeviceImpl_EndScene,
7727 IWineD3DDeviceImpl_Present,
7728 IWineD3DDeviceImpl_Clear,
7729 IWineD3DDeviceImpl_ClearRendertargetView,
7730 /*** Drawing ***/
7731 IWineD3DDeviceImpl_SetPrimitiveType,
7732 IWineD3DDeviceImpl_GetPrimitiveType,
7733 IWineD3DDeviceImpl_DrawPrimitive,
7734 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7735 IWineD3DDeviceImpl_DrawPrimitiveUP,
7736 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7737 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7738 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7739 IWineD3DDeviceImpl_DrawRectPatch,
7740 IWineD3DDeviceImpl_DrawTriPatch,
7741 IWineD3DDeviceImpl_DeletePatch,
7742 IWineD3DDeviceImpl_ColorFill,
7743 IWineD3DDeviceImpl_UpdateTexture,
7744 IWineD3DDeviceImpl_UpdateSurface,
7745 IWineD3DDeviceImpl_GetFrontBufferData,
7746 /*** object tracking ***/
7747 IWineD3DDeviceImpl_EnumResources
7748};
7749
7750const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7751 WINED3DRS_ALPHABLENDENABLE ,
7752 WINED3DRS_ALPHAFUNC ,
7753 WINED3DRS_ALPHAREF ,
7754 WINED3DRS_ALPHATESTENABLE ,
7755 WINED3DRS_BLENDOP ,
7756 WINED3DRS_COLORWRITEENABLE ,
7757 WINED3DRS_DESTBLEND ,
7758 WINED3DRS_DITHERENABLE ,
7759 WINED3DRS_FILLMODE ,
7760 WINED3DRS_FOGDENSITY ,
7761 WINED3DRS_FOGEND ,
7762 WINED3DRS_FOGSTART ,
7763 WINED3DRS_LASTPIXEL ,
7764 WINED3DRS_SHADEMODE ,
7765 WINED3DRS_SRCBLEND ,
7766 WINED3DRS_STENCILENABLE ,
7767 WINED3DRS_STENCILFAIL ,
7768 WINED3DRS_STENCILFUNC ,
7769 WINED3DRS_STENCILMASK ,
7770 WINED3DRS_STENCILPASS ,
7771 WINED3DRS_STENCILREF ,
7772 WINED3DRS_STENCILWRITEMASK ,
7773 WINED3DRS_STENCILZFAIL ,
7774 WINED3DRS_TEXTUREFACTOR ,
7775 WINED3DRS_WRAP0 ,
7776 WINED3DRS_WRAP1 ,
7777 WINED3DRS_WRAP2 ,
7778 WINED3DRS_WRAP3 ,
7779 WINED3DRS_WRAP4 ,
7780 WINED3DRS_WRAP5 ,
7781 WINED3DRS_WRAP6 ,
7782 WINED3DRS_WRAP7 ,
7783 WINED3DRS_ZENABLE ,
7784 WINED3DRS_ZFUNC ,
7785 WINED3DRS_ZWRITEENABLE
7786};
7787
7788const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7789 WINED3DTSS_ALPHAARG0 ,
7790 WINED3DTSS_ALPHAARG1 ,
7791 WINED3DTSS_ALPHAARG2 ,
7792 WINED3DTSS_ALPHAOP ,
7793 WINED3DTSS_BUMPENVLOFFSET ,
7794 WINED3DTSS_BUMPENVLSCALE ,
7795 WINED3DTSS_BUMPENVMAT00 ,
7796 WINED3DTSS_BUMPENVMAT01 ,
7797 WINED3DTSS_BUMPENVMAT10 ,
7798 WINED3DTSS_BUMPENVMAT11 ,
7799 WINED3DTSS_COLORARG0 ,
7800 WINED3DTSS_COLORARG1 ,
7801 WINED3DTSS_COLORARG2 ,
7802 WINED3DTSS_COLOROP ,
7803 WINED3DTSS_RESULTARG ,
7804 WINED3DTSS_TEXCOORDINDEX ,
7805 WINED3DTSS_TEXTURETRANSFORMFLAGS
7806};
7807
7808const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7809 WINED3DSAMP_ADDRESSU ,
7810 WINED3DSAMP_ADDRESSV ,
7811 WINED3DSAMP_ADDRESSW ,
7812 WINED3DSAMP_BORDERCOLOR ,
7813 WINED3DSAMP_MAGFILTER ,
7814 WINED3DSAMP_MINFILTER ,
7815 WINED3DSAMP_MIPFILTER ,
7816 WINED3DSAMP_MIPMAPLODBIAS ,
7817 WINED3DSAMP_MAXMIPLEVEL ,
7818 WINED3DSAMP_MAXANISOTROPY ,
7819 WINED3DSAMP_SRGBTEXTURE ,
7820 WINED3DSAMP_ELEMENTINDEX
7821};
7822
7823const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7824 WINED3DRS_AMBIENT ,
7825 WINED3DRS_AMBIENTMATERIALSOURCE ,
7826 WINED3DRS_CLIPPING ,
7827 WINED3DRS_CLIPPLANEENABLE ,
7828 WINED3DRS_COLORVERTEX ,
7829 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7830 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7831 WINED3DRS_FOGDENSITY ,
7832 WINED3DRS_FOGEND ,
7833 WINED3DRS_FOGSTART ,
7834 WINED3DRS_FOGTABLEMODE ,
7835 WINED3DRS_FOGVERTEXMODE ,
7836 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7837 WINED3DRS_LIGHTING ,
7838 WINED3DRS_LOCALVIEWER ,
7839 WINED3DRS_MULTISAMPLEANTIALIAS ,
7840 WINED3DRS_MULTISAMPLEMASK ,
7841 WINED3DRS_NORMALIZENORMALS ,
7842 WINED3DRS_PATCHEDGESTYLE ,
7843 WINED3DRS_POINTSCALE_A ,
7844 WINED3DRS_POINTSCALE_B ,
7845 WINED3DRS_POINTSCALE_C ,
7846 WINED3DRS_POINTSCALEENABLE ,
7847 WINED3DRS_POINTSIZE ,
7848 WINED3DRS_POINTSIZE_MAX ,
7849 WINED3DRS_POINTSIZE_MIN ,
7850 WINED3DRS_POINTSPRITEENABLE ,
7851 WINED3DRS_RANGEFOGENABLE ,
7852 WINED3DRS_SPECULARMATERIALSOURCE ,
7853 WINED3DRS_TWEENFACTOR ,
7854 WINED3DRS_VERTEXBLEND ,
7855 WINED3DRS_CULLMODE ,
7856 WINED3DRS_FOGCOLOR
7857};
7858
7859const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7860 WINED3DTSS_TEXCOORDINDEX ,
7861 WINED3DTSS_TEXTURETRANSFORMFLAGS
7862};
7863
7864const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7865 WINED3DSAMP_DMAPOFFSET
7866};
7867
7868void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7869 DWORD rep = This->StateTable[state].representative;
7870 DWORD idx;
7871 BYTE shift;
7872 UINT i;
7873 WineD3DContext *context;
7874
7875 if(!rep) return;
7876 for(i = 0; i < This->numContexts; i++) {
7877 context = This->contexts[i];
7878 if(isStateDirty(context, rep)) continue;
7879
7880 context->dirtyArray[context->numDirtyEntries++] = rep;
7881 idx = rep >> 5;
7882 shift = rep & 0x1f;
7883 context->isStateDirty[idx] |= (1 << shift);
7884 }
7885}
7886
7887void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7888 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7889 /* The drawable size of a pbuffer render target is the current pbuffer size
7890 */
7891 *width = dev->pbufferWidth;
7892 *height = dev->pbufferHeight;
7893}
7894
7895void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7896 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7897 */
7898 *width = This->pow2Width;
7899 *height = This->pow2Height;
7900}
7901
7902void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7903 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7904 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7905 * current context's drawable, which is the size of the back buffer of the swapchain
7906 * the active context belongs to. The back buffer of the swapchain is stored as the
7907 * surface the context belongs to.
7908 */
7909 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7910 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;
7911}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette