VirtualBox

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

Last change on this file since 22496 was 22496, checked in by vboxsync, 15 years ago

crOpenGL: update wine to 1.1.27 and better fix for depthstencil surface refcounting

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

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