VirtualBox

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

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

crOpenGL: update to wine 1.1.36 and disable unnecessary fbo state poll

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

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