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