wined3d: Remove the format field from IWineD3DResourceClass.
[wine/multimedia.git] / dlls / wined3d / device.c
blob7f1840f4ddd3d30b1343ee6c69a1fba2fdfd399a
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
69 return GL_POINTS;
71 case WINED3DPT_LINELIST:
72 return GL_LINES;
74 case WINED3DPT_LINESTRIP:
75 return GL_LINE_STRIP;
77 case WINED3DPT_TRIANGLELIST:
78 return GL_TRIANGLES;
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
98 default:
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
100 return GL_NONE;
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
108 case GL_POINTS:
109 return WINED3DPT_POINTLIST;
111 case GL_LINES:
112 return WINED3DPT_LINELIST;
114 case GL_LINE_STRIP:
115 return WINED3DPT_LINESTRIP;
117 case GL_TRIANGLES:
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
138 default:
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
145 /**********************************************************
146 * IUnknown parts follows
147 **********************************************************/
149 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
154 if (IsEqualGUID(riid, &IID_IUnknown)
155 || IsEqualGUID(riid, &IID_IWineD3DBase)
156 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
157 IUnknown_AddRef(iface);
158 *ppobj = This;
159 return S_OK;
161 *ppobj = NULL;
162 return E_NOINTERFACE;
165 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
167 ULONG refCount = InterlockedIncrement(&This->ref);
169 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
170 return refCount;
173 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
175 ULONG refCount = InterlockedDecrement(&This->ref);
177 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
179 if (!refCount) {
180 UINT i;
182 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
183 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
184 This->multistate_funcs[i] = NULL;
187 /* TODO: Clean up all the surfaces and textures! */
188 /* NOTE: You must release the parent if the object was created via a callback
189 ** ***************************/
191 if (!list_empty(&This->resources)) {
192 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
193 dumpResources(&This->resources);
196 if(This->contexts) ERR("Context array not freed!\n");
197 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
198 This->haveHardwareCursor = FALSE;
200 IWineD3D_Release(This->wineD3D);
201 This->wineD3D = NULL;
202 HeapFree(GetProcessHeap(), 0, This);
203 TRACE("Freed device %p\n", This);
204 This = NULL;
206 return refCount;
209 /**********************************************************
210 * IWineD3DDevice implementation follows
211 **********************************************************/
212 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 *pParent = This->parent;
215 IUnknown_AddRef(This->parent);
216 return WINED3D_OK;
219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
220 struct wined3d_buffer_desc *desc, IUnknown *parent, IWineD3DBuffer **buffer)
222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
223 struct wined3d_buffer *object;
224 HRESULT hr;
226 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
229 if (!object)
231 ERR("Failed to allocate memory\n");
232 return E_OUTOFMEMORY;
235 object->vtbl = &wined3d_buffer_vtbl;
236 object->desc = *desc;
238 FIXME("Ignoring access flags (pool)\n");
240 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
241 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
242 if (FAILED(hr))
244 WARN("Failed to initialize resource, returning %#x\n", hr);
245 HeapFree(GetProcessHeap(), 0, object);
246 return hr;
249 TRACE("Created resource %p\n", object);
251 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
253 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
254 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
256 *buffer = (IWineD3DBuffer *)object;
258 return WINED3D_OK;
261 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
262 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
265 /* Dummy format for now */
266 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
267 struct wined3d_buffer *object;
268 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
269 HRESULT hr;
270 BOOL conv;
272 if(Size == 0) {
273 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
274 *ppVertexBuffer = NULL;
275 return WINED3DERR_INVALIDCALL;
276 } else if(Pool == WINED3DPOOL_SCRATCH) {
277 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
278 * anyway, SCRATCH vertex buffers aren't usable anywhere
280 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
281 *ppVertexBuffer = NULL;
282 return WINED3DERR_INVALIDCALL;
285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
286 if (!object)
288 ERR("Out of memory\n");
289 *ppVertexBuffer = NULL;
290 return WINED3DERR_OUTOFVIDEOMEMORY;
293 object->vtbl = &wined3d_buffer_vtbl;
294 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, format_desc, Pool, parent);
295 if (FAILED(hr))
297 WARN("Failed to initialize resource, returning %#x\n", hr);
298 HeapFree(GetProcessHeap(), 0, object);
299 *ppVertexBuffer = NULL;
300 return hr;
303 TRACE("(%p) : Created resource %p\n", This, object);
305 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
307 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
308 *ppVertexBuffer = (IWineD3DBuffer *)object;
310 object->fvf = FVF;
312 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
313 * drawStridedFast (half-life 2).
315 * Basically converting the vertices in the buffer is quite expensive, and observations
316 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
317 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
319 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
320 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
321 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
322 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
323 * dx7 apps.
324 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
325 * more. In this call we can convert dx7 buffers too.
327 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
328 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
329 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
330 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
331 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
332 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
333 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
334 } else if(dxVersion <= 7 && conv) {
335 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
336 } else {
337 object->flags |= WINED3D_BUFFER_CREATEBO;
339 return WINED3D_OK;
342 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
343 GLenum error, glUsage;
344 TRACE("Creating VBO for Index Buffer %p\n", object);
346 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
347 * restored on the next draw
349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
351 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
352 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
353 ENTER_GL();
355 while(glGetError());
357 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
358 error = glGetError();
359 if(error != GL_NO_ERROR || object->vbo == 0) {
360 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
361 goto out;
364 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
365 error = glGetError();
366 if(error != GL_NO_ERROR) {
367 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
368 goto out;
371 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
372 * copy no readback will be needed
374 glUsage = GL_STATIC_DRAW_ARB;
375 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
376 error = glGetError();
377 if(error != GL_NO_ERROR) {
378 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
379 goto out;
381 LEAVE_GL();
382 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
383 return;
385 out:
386 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
387 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
388 LEAVE_GL();
389 object->vbo = 0;
392 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
393 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
394 HANDLE *sharedHandle, IUnknown *parent) {
395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
397 IWineD3DIndexBufferImpl *object;
398 HRESULT hr;
400 TRACE("(%p) Creating index buffer\n", This);
402 /* Allocate the storage for the device */
403 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
404 if (!object)
406 ERR("Out of memory\n");
407 *ppIndexBuffer = NULL;
408 return WINED3DERR_OUTOFVIDEOMEMORY;
411 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
412 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, format_desc, Pool, parent);
413 if (FAILED(hr))
415 WARN("Failed to initialize resource, returning %#x\n", hr);
416 HeapFree(GetProcessHeap(), 0, object);
417 *ppIndexBuffer = NULL;
418 return hr;
421 TRACE("(%p) : Created resource %p\n", This, object);
423 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
433 return WINED3D_OK;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
440 int i, j;
441 HRESULT temp_result;
443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
444 if(!object)
446 ERR("Out of memory\n");
447 *ppStateBlock = NULL;
448 return WINED3DERR_OUTOFVIDEOMEMORY;
451 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
452 object->wineD3DDevice = This;
453 object->parent = parent;
454 object->ref = 1;
455 object->blockType = Type;
457 *ppStateBlock = (IWineD3DStateBlock *)object;
459 for(i = 0; i < LIGHTMAP_SIZE; i++) {
460 list_init(&object->lightMap[i]);
463 temp_result = allocate_shader_constants(object);
464 if (FAILED(temp_result))
466 HeapFree(GetProcessHeap(), 0, object);
467 return temp_result;
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
474 /* Don't bother increasing the reference count otherwise a device will never
475 be freed due to circular dependencies */
476 return WINED3D_OK;
479 /* Otherwise, might as well set the whole state block to the appropriate values */
480 if (This->stateBlock != NULL)
481 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
482 else
483 memset(object->streamFreq, 1, sizeof(object->streamFreq));
485 /* Reset the ref and type after kludging it */
486 object->wineD3DDevice = This;
487 object->ref = 1;
488 object->blockType = Type;
490 TRACE("Updating changed flags appropriate for type %d\n", Type);
492 if (Type == WINED3DSBT_ALL) {
494 TRACE("ALL => Pretend everything has changed\n");
495 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
497 /* Lights are not part of the changed / set structure */
498 for(j = 0; j < LIGHTMAP_SIZE; j++) {
499 struct list *e;
500 LIST_FOR_EACH(e, &object->lightMap[j]) {
501 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
502 light->changed = TRUE;
503 light->enabledChanged = TRUE;
506 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
507 object->contained_render_states[j - 1] = j;
509 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
510 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
511 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
512 object->contained_transform_states[j - 1] = j;
514 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
515 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
516 object->contained_vs_consts_f[j] = j;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for(j = 0; j < MAX_CONST_I; j++) {
520 object->contained_vs_consts_i[j] = j;
522 object->num_contained_vs_consts_i = MAX_CONST_I;
523 for(j = 0; j < MAX_CONST_B; j++) {
524 object->contained_vs_consts_b[j] = j;
526 object->num_contained_vs_consts_b = MAX_CONST_B;
527 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
528 object->contained_ps_consts_f[j] = j;
530 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
531 for(j = 0; j < MAX_CONST_I; j++) {
532 object->contained_ps_consts_i[j] = j;
534 object->num_contained_ps_consts_i = MAX_CONST_I;
535 for(j = 0; j < MAX_CONST_B; j++) {
536 object->contained_ps_consts_b[j] = j;
538 object->num_contained_ps_consts_b = MAX_CONST_B;
539 for(i = 0; i < MAX_TEXTURES; i++) {
540 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
542 object->contained_tss_states[object->num_contained_tss_states].stage = i;
543 object->contained_tss_states[object->num_contained_tss_states].state = j;
544 object->num_contained_tss_states++;
547 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
548 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
549 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
550 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
551 object->num_contained_sampler_states++;
555 for(i = 0; i < MAX_STREAMS; i++) {
556 if(object->streamSource[i]) {
557 IWineD3DBuffer_AddRef(object->streamSource[i]);
560 if(object->pIndexData) {
561 IWineD3DIndexBuffer_AddRef(object->pIndexData);
563 if(object->vertexShader) {
564 IWineD3DVertexShader_AddRef(object->vertexShader);
566 if(object->pixelShader) {
567 IWineD3DPixelShader_AddRef(object->pixelShader);
570 } else if (Type == WINED3DSBT_PIXELSTATE) {
572 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
573 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
575 object->changed.pixelShader = TRUE;
577 /* Pixel Shader Constants */
578 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
579 object->contained_ps_consts_f[i] = i;
580 object->changed.pixelShaderConstantsF[i] = TRUE;
582 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
583 for (i = 0; i < MAX_CONST_B; ++i) {
584 object->contained_ps_consts_b[i] = i;
585 object->changed.pixelShaderConstantsB |= (1 << i);
587 object->num_contained_ps_consts_b = MAX_CONST_B;
588 for (i = 0; i < MAX_CONST_I; ++i) {
589 object->contained_ps_consts_i[i] = i;
590 object->changed.pixelShaderConstantsI |= (1 << i);
592 object->num_contained_ps_consts_i = MAX_CONST_I;
594 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
595 DWORD rs = SavedPixelStates_R[i];
596 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
597 object->contained_render_states[i] = rs;
599 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
600 for (j = 0; j < MAX_TEXTURES; j++) {
601 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
602 DWORD state = SavedPixelStates_T[i];
603 object->changed.textureState[j] |= 1 << state;
604 object->contained_tss_states[object->num_contained_tss_states].stage = j;
605 object->contained_tss_states[object->num_contained_tss_states].state = state;
606 object->num_contained_tss_states++;
609 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
610 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
611 DWORD state = SavedPixelStates_S[i];
612 object->changed.samplerState[j] |= 1 << state;
613 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
614 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
615 object->num_contained_sampler_states++;
618 if(object->pixelShader) {
619 IWineD3DPixelShader_AddRef(object->pixelShader);
622 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
623 * on them. This makes releasing the buffer easier
625 for(i = 0; i < MAX_STREAMS; i++) {
626 object->streamSource[i] = NULL;
628 object->pIndexData = NULL;
629 object->vertexShader = NULL;
631 } else if (Type == WINED3DSBT_VERTEXSTATE) {
633 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
634 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
636 object->changed.vertexShader = TRUE;
638 /* Vertex Shader Constants */
639 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
640 object->changed.vertexShaderConstantsF[i] = TRUE;
641 object->contained_vs_consts_f[i] = i;
643 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
644 for (i = 0; i < MAX_CONST_B; ++i) {
645 object->contained_vs_consts_b[i] = i;
646 object->changed.vertexShaderConstantsB |= (1 << i);
648 object->num_contained_vs_consts_b = MAX_CONST_B;
649 for (i = 0; i < MAX_CONST_I; ++i) {
650 object->contained_vs_consts_i[i] = i;
651 object->changed.vertexShaderConstantsI |= (1 << i);
653 object->num_contained_vs_consts_i = MAX_CONST_I;
654 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
655 DWORD rs = SavedVertexStates_R[i];
656 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
657 object->contained_render_states[i] = rs;
659 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
660 for (j = 0; j < MAX_TEXTURES; j++) {
661 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
662 DWORD state = SavedVertexStates_T[i];
663 object->changed.textureState[j] |= 1 << state;
664 object->contained_tss_states[object->num_contained_tss_states].stage = j;
665 object->contained_tss_states[object->num_contained_tss_states].state = state;
666 object->num_contained_tss_states++;
669 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
670 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
671 DWORD state = SavedVertexStates_S[i];
672 object->changed.samplerState[j] |= 1 << state;
673 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
674 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
675 object->num_contained_sampler_states++;
679 for(j = 0; j < LIGHTMAP_SIZE; j++) {
680 struct list *e;
681 LIST_FOR_EACH(e, &object->lightMap[j]) {
682 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
683 light->changed = TRUE;
684 light->enabledChanged = TRUE;
688 for(i = 0; i < MAX_STREAMS; i++) {
689 if(object->streamSource[i]) {
690 IWineD3DBuffer_AddRef(object->streamSource[i]);
693 if(object->vertexShader) {
694 IWineD3DVertexShader_AddRef(object->vertexShader);
696 object->pIndexData = NULL;
697 object->pixelShader = NULL;
698 } else {
699 FIXME("Unrecognized state block type %d\n", Type);
702 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
703 return WINED3D_OK;
706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
708 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
709 unsigned int Size = 1;
710 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
711 UINT mul_4w, mul_4h;
712 HRESULT hr;
714 TRACE("(%p) Create surface\n",This);
716 if(MultisampleQuality > 0) {
717 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
718 MultisampleQuality=0;
721 /** FIXME: Check that the format is supported
722 * by the device.
723 *******************************/
725 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
726 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
727 * space!
728 *********************************/
729 mul_4w = (Width + 3) & ~3;
730 mul_4h = (Height + 3) & ~3;
731 if (WINED3DFMT_UNKNOWN == Format) {
732 Size = 0;
733 } else if (Format == WINED3DFMT_DXT1) {
734 /* DXT1 is half byte per pixel */
735 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
737 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
738 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
739 Format == WINED3DFMT_ATI2N) {
740 Size = (mul_4w * glDesc->byte_count * mul_4h);
741 } else {
742 /* The pitch is a multiple of 4 bytes */
743 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
744 Size *= Height;
747 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
749 /** Create and initialise the surface resource **/
750 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
751 if (!object)
753 ERR("Out of memory\n");
754 *ppSurface = NULL;
755 return WINED3DERR_OUTOFVIDEOMEMORY;
758 /* Look at the implementation and set the correct Vtable */
759 switch(Impl)
761 case SURFACE_OPENGL:
762 /* Check if a 3D adapter is available when creating gl surfaces */
763 if (!This->adapter)
765 ERR("OpenGL surfaces are not available without opengl\n");
766 HeapFree(GetProcessHeap(), 0, object);
767 return WINED3DERR_NOTAVAILABLE;
769 object->lpVtbl = &IWineD3DSurface_Vtbl;
770 break;
772 case SURFACE_GDI:
773 object->lpVtbl = &IWineGDISurface_Vtbl;
774 break;
776 default:
777 /* To be sure to catch this */
778 ERR("Unknown requested surface implementation %d!\n", Impl);
779 HeapFree(GetProcessHeap(), 0, object);
780 return WINED3DERR_INVALIDCALL;
783 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
784 if (FAILED(hr))
786 WARN("Failed to initialize resource, returning %#x\n", hr);
787 HeapFree(GetProcessHeap(), 0, object);
788 *ppSurface = NULL;
789 return hr;
792 TRACE("(%p) : Created resource %p\n", This, object);
794 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
796 *ppSurface = (IWineD3DSurface *)object;
798 /* "Standalone" surface */
799 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
801 object->currentDesc.Width = Width;
802 object->currentDesc.Height = Height;
803 object->currentDesc.MultiSampleType = MultiSample;
804 object->currentDesc.MultiSampleQuality = MultisampleQuality;
805 object->glDescription.level = Level;
806 list_init(&object->overlays);
808 /* Flags */
809 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
810 object->Flags |= Discard ? SFLAG_DISCARD : 0;
811 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
812 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
815 if (WINED3DFMT_UNKNOWN != Format) {
816 object->bytesPerPixel = glDesc->byte_count;
817 } else {
818 object->bytesPerPixel = 0;
821 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
823 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
825 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
826 * this function is too deep to need to care about things like this.
827 * Levels need to be checked too, and possibly Type since they all affect what can be done.
828 * ****************************************/
829 switch(Pool) {
830 case WINED3DPOOL_SCRATCH:
831 if(!Lockable)
832 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
833 "which are mutually exclusive, setting lockable to TRUE\n");
834 Lockable = TRUE;
835 break;
836 case WINED3DPOOL_SYSTEMMEM:
837 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
838 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
839 case WINED3DPOOL_MANAGED:
840 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
841 "Usage of DYNAMIC which are mutually exclusive, not doing "
842 "anything just telling you.\n");
843 break;
844 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
845 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
846 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
847 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
848 break;
849 default:
850 FIXME("(%p) Unknown pool %d\n", This, Pool);
851 break;
854 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
855 FIXME("Trying to create a render target that isn't in the default pool\n");
858 /* mark the texture as dirty so that it gets loaded first time around*/
859 surface_add_dirty_rect(*ppSurface, NULL);
860 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
861 This, Width, Height, Format, debug_d3dformat(Format),
862 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
864 list_init(&object->renderbuffers);
866 /* Call the private setup routine */
867 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
868 if (FAILED(hr))
870 ERR("Private setup failed, returning %#x\n", hr);
871 IWineD3DSurface_Release(*ppSurface);
872 *ppSurface = NULL;
873 return hr;
876 return hr;
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
880 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
882 struct wined3d_rendertarget_view *object;
884 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
885 if (!object)
887 ERR("Failed to allocate memory\n");
888 return E_OUTOFMEMORY;
891 object->vtbl = &wined3d_rendertarget_view_vtbl;
892 object->refcount = 1;
893 IWineD3DResource_AddRef(resource);
894 object->resource = resource;
895 object->parent = parent;
897 *rendertarget_view = (IWineD3DRendertargetView *)object;
899 return WINED3D_OK;
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
903 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
907 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
908 IWineD3DTextureImpl *object;
909 unsigned int i;
910 UINT tmpW;
911 UINT tmpH;
912 HRESULT hr;
913 unsigned int pow2Width;
914 unsigned int pow2Height;
916 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
917 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
918 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
920 /* TODO: It should only be possible to create textures for formats
921 that are reported as supported */
922 if (WINED3DFMT_UNKNOWN >= Format) {
923 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
924 return WINED3DERR_INVALIDCALL;
927 /* Non-power2 support */
928 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
930 pow2Width = Width;
931 pow2Height = Height;
933 else
935 /* Find the nearest pow2 match */
936 pow2Width = pow2Height = 1;
937 while (pow2Width < Width) pow2Width <<= 1;
938 while (pow2Height < Height) pow2Height <<= 1;
940 if (pow2Width != Width || pow2Height != Height)
942 if (Levels > 1)
944 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
945 return WINED3DERR_INVALIDCALL;
947 Levels = 1;
951 /* Calculate levels for mip mapping */
952 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
954 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
960 if (Levels > 1)
962 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL;
966 Levels = 1;
968 else if (!Levels)
970 Levels = wined3d_log2i(max(Width, Height)) + 1;
971 TRACE("Calculated levels = %d\n", Levels);
974 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
975 if (!object)
977 ERR("Out of memory\n");
978 *ppTexture = NULL;
979 return WINED3DERR_OUTOFVIDEOMEMORY;
982 object->lpVtbl = &IWineD3DTexture_Vtbl;
983 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
984 if (FAILED(hr))
986 WARN("Failed to initialize resource, returning %#x\n", hr);
987 HeapFree(GetProcessHeap(), 0, object);
988 *ppTexture = NULL;
989 return hr;
992 TRACE("(%p) : Created resource %p\n", This, object);
994 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
996 *ppTexture = (IWineD3DTexture *)object;
998 basetexture_init(&object->baseTexture, Levels, Usage);
1000 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1002 object->baseTexture.minMipLookup = minMipLookup;
1003 object->baseTexture.magLookup = magLookup;
1004 } else {
1005 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1006 object->baseTexture.magLookup = magLookup_noFilter;
1009 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1010 /* Precalculated scaling for 'faked' non power of two texture coords.
1011 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1012 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1013 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1015 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1016 object->baseTexture.pow2Matrix[0] = 1.0;
1017 object->baseTexture.pow2Matrix[5] = 1.0;
1018 object->baseTexture.pow2Matrix[10] = 1.0;
1019 object->baseTexture.pow2Matrix[15] = 1.0;
1020 object->target = GL_TEXTURE_2D;
1021 object->cond_np2 = TRUE;
1022 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1023 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1024 (Width != pow2Width || Height != pow2Height) &&
1025 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1027 object->baseTexture.pow2Matrix[0] = (float)Width;
1028 object->baseTexture.pow2Matrix[5] = (float)Height;
1029 object->baseTexture.pow2Matrix[10] = 1.0;
1030 object->baseTexture.pow2Matrix[15] = 1.0;
1031 object->target = GL_TEXTURE_RECTANGLE_ARB;
1032 object->cond_np2 = TRUE;
1033 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1034 } else {
1035 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1036 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1037 object->baseTexture.pow2Matrix[10] = 1.0;
1038 object->baseTexture.pow2Matrix[15] = 1.0;
1039 object->target = GL_TEXTURE_2D;
1040 object->cond_np2 = FALSE;
1042 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1044 /* Generate all the surfaces */
1045 tmpW = Width;
1046 tmpH = Height;
1047 for (i = 0; i < object->baseTexture.levels; i++)
1049 /* use the callback to create the texture surface */
1050 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1051 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1052 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1053 FIXME("Failed to create surface %p\n", object);
1054 /* clean up */
1055 object->surfaces[i] = NULL;
1056 IWineD3DTexture_Release((IWineD3DTexture *)object);
1058 *ppTexture = NULL;
1059 return hr;
1062 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1063 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1064 surface_set_texture_target(object->surfaces[i], object->target);
1065 /* calculate the next mipmap level */
1066 tmpW = max(1, tmpW >> 1);
1067 tmpH = max(1, tmpH >> 1);
1069 object->baseTexture.internal_preload = texture_internal_preload;
1071 TRACE("(%p) : Created texture %p\n", This, object);
1072 return WINED3D_OK;
1075 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1076 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1077 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1080 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1081 IWineD3DVolumeTextureImpl *object;
1082 unsigned int i;
1083 UINT tmpW;
1084 UINT tmpH;
1085 UINT tmpD;
1086 HRESULT hr;
1088 /* TODO: It should only be possible to create textures for formats
1089 that are reported as supported */
1090 if (WINED3DFMT_UNKNOWN >= Format) {
1091 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1092 return WINED3DERR_INVALIDCALL;
1094 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1095 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1096 return WINED3DERR_INVALIDCALL;
1099 /* Calculate levels for mip mapping */
1100 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1102 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1104 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1105 return WINED3DERR_INVALIDCALL;
1108 if (Levels > 1)
1110 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1111 return WINED3DERR_INVALIDCALL;
1114 Levels = 1;
1116 else if (!Levels)
1118 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1119 TRACE("Calculated levels = %d\n", Levels);
1122 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1123 if (!object)
1125 ERR("Out of memory\n");
1126 *ppVolumeTexture = NULL;
1127 return WINED3DERR_OUTOFVIDEOMEMORY;
1130 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1131 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1132 if (FAILED(hr))
1134 WARN("Failed to initialize resource, returning %#x\n", hr);
1135 HeapFree(GetProcessHeap(), 0, object);
1136 *ppVolumeTexture = NULL;
1137 return hr;
1140 TRACE("(%p) : Created resource %p\n", This, object);
1142 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1144 basetexture_init(&object->baseTexture, Levels, Usage);
1146 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1147 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1149 /* Is NP2 support for volumes needed? */
1150 object->baseTexture.pow2Matrix[ 0] = 1.0;
1151 object->baseTexture.pow2Matrix[ 5] = 1.0;
1152 object->baseTexture.pow2Matrix[10] = 1.0;
1153 object->baseTexture.pow2Matrix[15] = 1.0;
1155 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1157 object->baseTexture.minMipLookup = minMipLookup;
1158 object->baseTexture.magLookup = magLookup;
1159 } else {
1160 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1161 object->baseTexture.magLookup = magLookup_noFilter;
1164 /* Generate all the surfaces */
1165 tmpW = Width;
1166 tmpH = Height;
1167 tmpD = Depth;
1169 for (i = 0; i < object->baseTexture.levels; i++)
1171 HRESULT hr;
1172 /* Create the volume */
1173 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1174 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1175 if(FAILED(hr)) {
1176 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1177 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1178 *ppVolumeTexture = NULL;
1179 return hr;
1182 /* Set its container to this object */
1183 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1185 /* calculate the next mipmap level */
1186 tmpW = max(1, tmpW >> 1);
1187 tmpH = max(1, tmpH >> 1);
1188 tmpD = max(1, tmpD >> 1);
1190 object->baseTexture.internal_preload = volumetexture_internal_preload;
1192 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1193 TRACE("(%p) : Created volume texture %p\n", This, object);
1194 return WINED3D_OK;
1197 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1198 UINT Width, UINT Height, UINT Depth,
1199 DWORD Usage,
1200 WINED3DFORMAT Format, WINED3DPOOL Pool,
1201 IWineD3DVolume** ppVolume,
1202 HANDLE* pSharedHandle, IUnknown *parent) {
1204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1205 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1206 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1207 HRESULT hr;
1209 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1210 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1211 return WINED3DERR_INVALIDCALL;
1214 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1215 if (!object)
1217 ERR("Out of memory\n");
1218 *ppVolume = NULL;
1219 return WINED3DERR_OUTOFVIDEOMEMORY;
1222 object->lpVtbl = &IWineD3DVolume_Vtbl;
1223 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1224 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1225 if (FAILED(hr))
1227 WARN("Failed to initialize resource, returning %#x\n", hr);
1228 HeapFree(GetProcessHeap(), 0, object);
1229 *ppVolume = NULL;
1230 return hr;
1233 TRACE("(%p) : Created resource %p\n", This, object);
1235 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1237 *ppVolume = (IWineD3DVolume *)object;
1239 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1240 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1242 object->currentDesc.Width = Width;
1243 object->currentDesc.Height = Height;
1244 object->currentDesc.Depth = Depth;
1245 object->bytesPerPixel = format_desc->byte_count;
1247 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1248 object->lockable = TRUE;
1249 object->locked = FALSE;
1250 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1251 object->dirty = TRUE;
1253 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1255 return WINED3D_OK;
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1259 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1260 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1263 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1264 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1265 unsigned int i, j;
1266 UINT tmpW;
1267 HRESULT hr;
1268 unsigned int pow2EdgeLength;
1270 /* TODO: It should only be possible to create textures for formats
1271 that are reported as supported */
1272 if (WINED3DFMT_UNKNOWN >= Format) {
1273 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1274 return WINED3DERR_INVALIDCALL;
1277 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1278 WARN("(%p) : Tried to create not supported cube texture\n", This);
1279 return WINED3DERR_INVALIDCALL;
1282 /* Calculate levels for mip mapping */
1283 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1285 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1287 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1288 return WINED3DERR_INVALIDCALL;
1291 if (Levels > 1)
1293 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1294 return WINED3DERR_INVALIDCALL;
1297 Levels = 1;
1299 else if (!Levels)
1301 Levels = wined3d_log2i(EdgeLength) + 1;
1302 TRACE("Calculated levels = %d\n", Levels);
1305 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1306 if (!object)
1308 ERR("Out of memory\n");
1309 *ppCubeTexture = NULL;
1310 return WINED3DERR_OUTOFVIDEOMEMORY;
1313 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1314 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1315 if (FAILED(hr))
1317 WARN("Failed to initialize resource, returning %#x\n", hr);
1318 HeapFree(GetProcessHeap(), 0, object);
1319 *ppCubeTexture = NULL;
1320 return hr;
1323 TRACE("(%p) : Created resource %p\n", This, object);
1325 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1327 basetexture_init(&object->baseTexture, Levels, Usage);
1329 TRACE("(%p) Create Cube Texture\n", This);
1331 /* Find the nearest pow2 match */
1332 pow2EdgeLength = 1;
1333 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1335 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1336 /* Precalculated scaling for 'faked' non power of two texture coords */
1337 object->baseTexture.pow2Matrix[ 0] = 1.0;
1338 object->baseTexture.pow2Matrix[ 5] = 1.0;
1339 object->baseTexture.pow2Matrix[10] = 1.0;
1340 object->baseTexture.pow2Matrix[15] = 1.0;
1341 } else {
1342 /* Precalculated scaling for 'faked' non power of two texture coords */
1343 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1344 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1345 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1346 object->baseTexture.pow2Matrix[15] = 1.0;
1349 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1351 object->baseTexture.minMipLookup = minMipLookup;
1352 object->baseTexture.magLookup = magLookup;
1353 } else {
1354 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1355 object->baseTexture.magLookup = magLookup_noFilter;
1358 /* Generate all the surfaces */
1359 tmpW = EdgeLength;
1360 for (i = 0; i < object->baseTexture.levels; i++) {
1362 /* Create the 6 faces */
1363 for (j = 0; j < 6; j++) {
1364 static const GLenum cube_targets[6] = {
1365 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1366 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1367 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1368 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1369 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1370 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1373 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1374 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1375 if (FAILED(hr))
1377 FIXME("(%p) Failed to create surface\n",object);
1378 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1379 *ppCubeTexture = NULL;
1380 return hr;
1382 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1383 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1384 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1386 tmpW = max(1, tmpW >> 1);
1388 object->baseTexture.internal_preload = cubetexture_internal_preload;
1390 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1391 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1392 return WINED3D_OK;
1395 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1397 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1398 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1399 const IWineD3DQueryVtbl *vtable;
1401 /* Just a check to see if we support this type of query */
1402 switch(Type) {
1403 case WINED3DQUERYTYPE_OCCLUSION:
1404 TRACE("(%p) occlusion query\n", This);
1405 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1406 hr = WINED3D_OK;
1407 else
1408 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1410 vtable = &IWineD3DOcclusionQuery_Vtbl;
1411 break;
1413 case WINED3DQUERYTYPE_EVENT:
1414 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1415 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1416 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1418 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1420 vtable = &IWineD3DEventQuery_Vtbl;
1421 hr = WINED3D_OK;
1422 break;
1424 case WINED3DQUERYTYPE_VCACHE:
1425 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1426 case WINED3DQUERYTYPE_VERTEXSTATS:
1427 case WINED3DQUERYTYPE_TIMESTAMP:
1428 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1429 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1430 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1431 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1432 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1433 case WINED3DQUERYTYPE_PIXELTIMINGS:
1434 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1435 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1436 default:
1437 /* Use the base Query vtable until we have a special one for each query */
1438 vtable = &IWineD3DQuery_Vtbl;
1439 FIXME("(%p) Unhandled query type %d\n", This, Type);
1441 if(NULL == ppQuery || hr != WINED3D_OK) {
1442 return hr;
1445 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1446 if(!object)
1448 ERR("Out of memory\n");
1449 *ppQuery = NULL;
1450 return WINED3DERR_OUTOFVIDEOMEMORY;
1453 object->lpVtbl = vtable;
1454 object->type = Type;
1455 object->state = QUERY_CREATED;
1456 object->wineD3DDevice = This;
1457 object->parent = parent;
1458 object->ref = 1;
1460 *ppQuery = (IWineD3DQuery *)object;
1462 /* allocated the 'extended' data based on the type of query requested */
1463 switch(Type){
1464 case WINED3DQUERYTYPE_OCCLUSION:
1465 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1466 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1468 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1469 TRACE("(%p) Allocating data for an occlusion query\n", This);
1471 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1472 ENTER_GL();
1473 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1474 LEAVE_GL();
1475 break;
1477 case WINED3DQUERYTYPE_EVENT:
1478 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1479 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1481 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1482 ENTER_GL();
1483 if(GL_SUPPORT(APPLE_FENCE)) {
1484 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1485 checkGLcall("glGenFencesAPPLE");
1486 } else if(GL_SUPPORT(NV_FENCE)) {
1487 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1488 checkGLcall("glGenFencesNV");
1490 LEAVE_GL();
1491 break;
1493 case WINED3DQUERYTYPE_VCACHE:
1494 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1495 case WINED3DQUERYTYPE_VERTEXSTATS:
1496 case WINED3DQUERYTYPE_TIMESTAMP:
1497 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1498 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1499 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1500 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1501 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1502 case WINED3DQUERYTYPE_PIXELTIMINGS:
1503 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1504 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1505 default:
1506 object->extendedData = 0;
1507 FIXME("(%p) Unhandled query type %d\n",This , Type);
1509 TRACE("(%p) : Created Query %p\n", This, object);
1510 return WINED3D_OK;
1513 /*****************************************************************************
1514 * IWineD3DDeviceImpl_SetupFullscreenWindow
1516 * Helper function that modifies a HWND's Style and ExStyle for proper
1517 * fullscreen use.
1519 * Params:
1520 * iface: Pointer to the IWineD3DDevice interface
1521 * window: Window to setup
1523 *****************************************************************************/
1524 static LONG fullscreen_style(LONG orig_style) {
1525 LONG style = orig_style;
1526 style &= ~WS_CAPTION;
1527 style &= ~WS_THICKFRAME;
1529 /* Make sure the window is managed, otherwise we won't get keyboard input */
1530 style |= WS_POPUP | WS_SYSMENU;
1532 return style;
1535 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1536 LONG exStyle = orig_exStyle;
1538 /* Filter out window decorations */
1539 exStyle &= ~WS_EX_WINDOWEDGE;
1540 exStyle &= ~WS_EX_CLIENTEDGE;
1542 return exStyle;
1545 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1548 LONG style, exStyle;
1549 /* Don't do anything if an original style is stored.
1550 * That shouldn't happen
1552 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1553 if (This->style || This->exStyle) {
1554 ERR("(%p): Want to change the window parameters of HWND %p, but "
1555 "another style is stored for restoration afterwards\n", This, window);
1558 /* Get the parameters and save them */
1559 style = GetWindowLongW(window, GWL_STYLE);
1560 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1561 This->style = style;
1562 This->exStyle = exStyle;
1564 style = fullscreen_style(style);
1565 exStyle = fullscreen_exStyle(exStyle);
1567 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1568 This->style, This->exStyle, style, exStyle);
1570 SetWindowLongW(window, GWL_STYLE, style);
1571 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1573 /* Inform the window about the update. */
1574 SetWindowPos(window, HWND_TOP, 0, 0,
1575 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1578 /*****************************************************************************
1579 * IWineD3DDeviceImpl_RestoreWindow
1581 * Helper function that restores a windows' properties when taking it out
1582 * of fullscreen mode
1584 * Params:
1585 * iface: Pointer to the IWineD3DDevice interface
1586 * window: Window to setup
1588 *****************************************************************************/
1589 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1591 LONG style, exStyle;
1593 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1594 * switch, do nothing
1596 if (!This->style && !This->exStyle) return;
1598 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1599 This, window, This->style, This->exStyle);
1601 style = GetWindowLongW(window, GWL_STYLE);
1602 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1604 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1605 * Some applications change it before calling Reset() when switching between windowed and
1606 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1608 if(style == fullscreen_style(This->style) &&
1609 exStyle == fullscreen_style(This->exStyle)) {
1610 SetWindowLongW(window, GWL_STYLE, This->style);
1611 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1614 /* Delete the old values */
1615 This->style = 0;
1616 This->exStyle = 0;
1618 /* Inform the window about the update */
1619 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1620 0, 0, 0, 0, /* Pos, Size, ignored */
1621 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1624 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1625 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1626 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1627 IUnknown *parent, WINED3DSURFTYPE surface_type)
1629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1631 HDC hDc;
1632 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1633 HRESULT hr;
1634 IUnknown *bufferParent;
1635 BOOL displaymode_set = FALSE;
1636 WINED3DDISPLAYMODE Mode;
1637 const struct GlPixelFormatDesc *format_desc;
1639 TRACE("(%p) : Created Additional Swap Chain\n", This);
1641 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1642 * does a device hold a reference to a swap chain giving them a lifetime of the device
1643 * or does the swap chain notify the device of its destruction.
1644 *******************************/
1646 /* Check the params */
1647 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1648 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1649 return WINED3DERR_INVALIDCALL;
1650 } else if (pPresentationParameters->BackBufferCount > 1) {
1651 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1654 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1655 if(!object)
1657 ERR("Out of memory\n");
1658 *ppSwapChain = NULL;
1659 return WINED3DERR_OUTOFVIDEOMEMORY;
1662 switch(surface_type) {
1663 case SURFACE_GDI:
1664 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1665 break;
1666 case SURFACE_OPENGL:
1667 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1668 break;
1669 case SURFACE_UNKNOWN:
1670 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1671 HeapFree(GetProcessHeap(), 0, object);
1672 return WINED3DERR_INVALIDCALL;
1674 object->wineD3DDevice = This;
1675 object->parent = parent;
1676 object->ref = 1;
1678 *ppSwapChain = (IWineD3DSwapChain *)object;
1680 /*********************
1681 * Lookup the window Handle and the relating X window handle
1682 ********************/
1684 /* Setup hwnd we are using, plus which display this equates to */
1685 object->win_handle = pPresentationParameters->hDeviceWindow;
1686 if (!object->win_handle) {
1687 object->win_handle = This->createParms.hFocusWindow;
1689 if(!pPresentationParameters->Windowed && object->win_handle) {
1690 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1691 pPresentationParameters->BackBufferWidth,
1692 pPresentationParameters->BackBufferHeight);
1695 hDc = GetDC(object->win_handle);
1696 TRACE("Using hDc %p\n", hDc);
1698 if (NULL == hDc) {
1699 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1700 return WINED3DERR_NOTAVAILABLE;
1703 /* Get info on the current display setup */
1704 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1705 object->orig_width = Mode.Width;
1706 object->orig_height = Mode.Height;
1707 object->orig_fmt = Mode.Format;
1708 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1710 if (pPresentationParameters->Windowed &&
1711 ((pPresentationParameters->BackBufferWidth == 0) ||
1712 (pPresentationParameters->BackBufferHeight == 0) ||
1713 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1715 RECT Rect;
1716 GetClientRect(object->win_handle, &Rect);
1718 if (pPresentationParameters->BackBufferWidth == 0) {
1719 pPresentationParameters->BackBufferWidth = Rect.right;
1720 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1722 if (pPresentationParameters->BackBufferHeight == 0) {
1723 pPresentationParameters->BackBufferHeight = Rect.bottom;
1724 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1726 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1727 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1728 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1732 /* Put the correct figures in the presentation parameters */
1733 TRACE("Copying across presentation parameters\n");
1734 object->presentParms = *pPresentationParameters;
1736 TRACE("calling rendertarget CB\n");
1737 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1738 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1739 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1740 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1741 if (SUCCEEDED(hr)) {
1742 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1743 if(surface_type == SURFACE_OPENGL) {
1744 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1746 } else {
1747 ERR("Failed to create the front buffer\n");
1748 goto error;
1751 /*********************
1752 * Windowed / Fullscreen
1753 *******************/
1756 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1757 * so we should really check to see if there is a fullscreen swapchain already
1758 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1759 **************************************/
1761 if (!pPresentationParameters->Windowed) {
1762 WINED3DDISPLAYMODE mode;
1765 /* Change the display settings */
1766 mode.Width = pPresentationParameters->BackBufferWidth;
1767 mode.Height = pPresentationParameters->BackBufferHeight;
1768 mode.Format = pPresentationParameters->BackBufferFormat;
1769 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1771 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1772 displaymode_set = TRUE;
1776 * Create an opengl context for the display visual
1777 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1778 * use different properties after that point in time. FIXME: How to handle when requested format
1779 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1780 * it chooses is identical to the one already being used!
1781 **********************************/
1782 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1784 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1785 if(!object->context) {
1786 ERR("Failed to create the context array\n");
1787 hr = E_OUTOFMEMORY;
1788 goto error;
1790 object->num_contexts = 1;
1792 if(surface_type == SURFACE_OPENGL) {
1793 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1794 if (!object->context[0]) {
1795 ERR("Failed to create a new context\n");
1796 hr = WINED3DERR_NOTAVAILABLE;
1797 goto error;
1798 } else {
1799 TRACE("Context created (HWND=%p, glContext=%p)\n",
1800 object->win_handle, object->context[0]->glCtx);
1804 /*********************
1805 * Create the back, front and stencil buffers
1806 *******************/
1807 if(object->presentParms.BackBufferCount > 0) {
1808 UINT i;
1810 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1811 if(!object->backBuffer) {
1812 ERR("Out of memory\n");
1813 hr = E_OUTOFMEMORY;
1814 goto error;
1817 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1818 TRACE("calling rendertarget CB\n");
1819 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1820 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1821 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1822 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1823 if(SUCCEEDED(hr)) {
1824 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1825 } else {
1826 ERR("Cannot create new back buffer\n");
1827 goto error;
1829 if(surface_type == SURFACE_OPENGL) {
1830 ENTER_GL();
1831 glDrawBuffer(GL_BACK);
1832 checkGLcall("glDrawBuffer(GL_BACK)");
1833 LEAVE_GL();
1836 } else {
1837 object->backBuffer = NULL;
1839 /* Single buffering - draw to front buffer */
1840 if(surface_type == SURFACE_OPENGL) {
1841 ENTER_GL();
1842 glDrawBuffer(GL_FRONT);
1843 checkGLcall("glDrawBuffer(GL_FRONT)");
1844 LEAVE_GL();
1848 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1849 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1850 TRACE("Creating depth stencil buffer\n");
1851 if (This->auto_depth_stencil_buffer == NULL ) {
1852 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1853 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1854 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1855 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1856 &This->auto_depth_stencil_buffer);
1857 if (SUCCEEDED(hr)) {
1858 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1859 } else {
1860 ERR("Failed to create the auto depth stencil\n");
1861 goto error;
1866 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1868 TRACE("Created swapchain %p\n", object);
1869 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1870 return WINED3D_OK;
1872 error:
1873 if (displaymode_set) {
1874 DEVMODEW devmode;
1875 RECT clip_rc;
1877 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1878 ClipCursor(NULL);
1880 /* Change the display settings */
1881 memset(&devmode, 0, sizeof(devmode));
1882 devmode.dmSize = sizeof(devmode);
1883 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1884 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1885 devmode.dmPelsWidth = object->orig_width;
1886 devmode.dmPelsHeight = object->orig_height;
1887 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1890 if (object->backBuffer) {
1891 UINT i;
1892 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1893 if(object->backBuffer[i]) {
1894 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1895 IUnknown_Release(bufferParent); /* once for the get parent */
1896 if (IUnknown_Release(bufferParent) > 0) {
1897 FIXME("(%p) Something's still holding the back buffer\n",This);
1901 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1902 object->backBuffer = NULL;
1904 if(object->context && object->context[0])
1905 DestroyContext(This, object->context[0]);
1906 if(object->frontBuffer) {
1907 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1908 IUnknown_Release(bufferParent); /* once for the get parent */
1909 if (IUnknown_Release(bufferParent) > 0) {
1910 FIXME("(%p) Something's still holding the front buffer\n",This);
1913 HeapFree(GetProcessHeap(), 0, object);
1914 return hr;
1917 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1918 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1920 TRACE("(%p)\n", This);
1922 return This->NumberOfSwapChains;
1925 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1929 if(iSwapChain < This->NumberOfSwapChains) {
1930 *pSwapChain = This->swapchains[iSwapChain];
1931 IWineD3DSwapChain_AddRef(*pSwapChain);
1932 TRACE("(%p) returning %p\n", This, *pSwapChain);
1933 return WINED3D_OK;
1934 } else {
1935 TRACE("Swapchain out of range\n");
1936 *pSwapChain = NULL;
1937 return WINED3DERR_INVALIDCALL;
1941 /*****
1942 * Vertex Declaration
1943 *****/
1944 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1945 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1947 IWineD3DVertexDeclarationImpl *object = NULL;
1948 HRESULT hr = WINED3D_OK;
1950 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1951 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1953 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1954 if(!object)
1956 ERR("Out of memory\n");
1957 *ppVertexDeclaration = NULL;
1958 return WINED3DERR_OUTOFVIDEOMEMORY;
1961 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1962 object->wineD3DDevice = This;
1963 object->parent = parent;
1964 object->ref = 1;
1966 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1968 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1969 if(FAILED(hr)) {
1970 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1971 *ppVertexDeclaration = NULL;
1974 return hr;
1977 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1978 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1980 unsigned int idx, idx2;
1981 unsigned int offset;
1982 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1983 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1984 BOOL has_blend_idx = has_blend &&
1985 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1986 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1987 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1988 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1989 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1990 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1991 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1993 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1994 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1996 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1997 WINED3DVERTEXELEMENT *elements = NULL;
1999 unsigned int size;
2000 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2001 if (has_blend_idx) num_blends--;
2003 /* Compute declaration size */
2004 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2005 has_psize + has_diffuse + has_specular + num_textures + 1;
2007 /* convert the declaration */
2008 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2009 if (!elements)
2010 return 0;
2012 elements[size-1] = end_element;
2013 idx = 0;
2014 if (has_pos) {
2015 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2016 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2017 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2019 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2020 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2021 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2023 else {
2024 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2025 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2027 elements[idx].UsageIndex = 0;
2028 idx++;
2030 if (has_blend && (num_blends > 0)) {
2031 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2032 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2033 else {
2034 switch(num_blends) {
2035 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2036 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2037 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2038 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2039 default:
2040 ERR("Unexpected amount of blend values: %u\n", num_blends);
2043 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2044 elements[idx].UsageIndex = 0;
2045 idx++;
2047 if (has_blend_idx) {
2048 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2049 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2050 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2051 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2052 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2053 else
2054 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2055 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2056 elements[idx].UsageIndex = 0;
2057 idx++;
2059 if (has_normal) {
2060 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2061 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2062 elements[idx].UsageIndex = 0;
2063 idx++;
2065 if (has_psize) {
2066 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2067 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2068 elements[idx].UsageIndex = 0;
2069 idx++;
2071 if (has_diffuse) {
2072 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2073 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2074 elements[idx].UsageIndex = 0;
2075 idx++;
2077 if (has_specular) {
2078 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2079 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2080 elements[idx].UsageIndex = 1;
2081 idx++;
2083 for (idx2 = 0; idx2 < num_textures; idx2++) {
2084 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2085 switch (numcoords) {
2086 case WINED3DFVF_TEXTUREFORMAT1:
2087 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2088 break;
2089 case WINED3DFVF_TEXTUREFORMAT2:
2090 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2091 break;
2092 case WINED3DFVF_TEXTUREFORMAT3:
2093 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2094 break;
2095 case WINED3DFVF_TEXTUREFORMAT4:
2096 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2097 break;
2099 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2100 elements[idx].UsageIndex = idx2;
2101 idx++;
2104 /* Now compute offsets, and initialize the rest of the fields */
2105 for (idx = 0, offset = 0; idx < size-1; idx++) {
2106 elements[idx].Stream = 0;
2107 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2108 elements[idx].Offset = offset;
2109 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2112 *ppVertexElements = elements;
2113 return size;
2116 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2117 WINED3DVERTEXELEMENT* elements = NULL;
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2119 unsigned int size;
2120 DWORD hr;
2122 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2123 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2125 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2126 HeapFree(GetProcessHeap(), 0, elements);
2127 if (hr != S_OK) return hr;
2129 return WINED3D_OK;
2132 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2134 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2135 HRESULT hr = WINED3D_OK;
2137 if (!pFunction) return WINED3DERR_INVALIDCALL;
2139 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2140 if (!object)
2142 ERR("Out of memory\n");
2143 *ppVertexShader = NULL;
2144 return WINED3DERR_OUTOFVIDEOMEMORY;
2147 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2148 object->parent = parent;
2149 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2150 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2151 *ppVertexShader = (IWineD3DVertexShader *)object;
2153 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2155 if (vertex_declaration) {
2156 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2159 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2160 if (FAILED(hr))
2162 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2163 IWineD3DVertexShader_Release(*ppVertexShader);
2164 *ppVertexShader = NULL;
2165 return hr;
2168 return hr;
2171 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2173 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2174 HRESULT hr = WINED3D_OK;
2176 if (!pFunction) return WINED3DERR_INVALIDCALL;
2178 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2179 if (!object)
2181 ERR("Out of memory\n");
2182 *ppPixelShader = NULL;
2183 return WINED3DERR_OUTOFVIDEOMEMORY;
2186 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2187 object->parent = parent;
2188 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2189 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2190 *ppPixelShader = (IWineD3DPixelShader *)object;
2192 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2194 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2195 if (FAILED(hr))
2197 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2198 IWineD3DPixelShader_Release(*ppPixelShader);
2199 *ppPixelShader = NULL;
2200 return hr;
2203 return hr;
2206 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2207 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2210 IWineD3DPaletteImpl *object;
2211 HRESULT hr;
2212 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2214 /* Create the new object */
2215 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2216 if(!object) {
2217 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2218 return E_OUTOFMEMORY;
2221 object->lpVtbl = &IWineD3DPalette_Vtbl;
2222 object->ref = 1;
2223 object->Flags = Flags;
2224 object->parent = Parent;
2225 object->wineD3DDevice = This;
2226 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2227 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2229 if(!object->hpal) {
2230 HeapFree( GetProcessHeap(), 0, object);
2231 return E_OUTOFMEMORY;
2234 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2235 if(FAILED(hr)) {
2236 IWineD3DPalette_Release((IWineD3DPalette *) object);
2237 return hr;
2240 *Palette = (IWineD3DPalette *) object;
2242 return WINED3D_OK;
2245 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2246 HBITMAP hbm;
2247 BITMAP bm;
2248 HRESULT hr;
2249 HDC dcb = NULL, dcs = NULL;
2250 WINEDDCOLORKEY colorkey;
2252 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2253 if(hbm)
2255 GetObjectA(hbm, sizeof(BITMAP), &bm);
2256 dcb = CreateCompatibleDC(NULL);
2257 if(!dcb) goto out;
2258 SelectObject(dcb, hbm);
2260 else
2262 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2263 * couldn't be loaded
2265 memset(&bm, 0, sizeof(bm));
2266 bm.bmWidth = 32;
2267 bm.bmHeight = 32;
2270 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2271 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2272 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2273 if(FAILED(hr)) {
2274 ERR("Wine logo requested, but failed to create surface\n");
2275 goto out;
2278 if(dcb) {
2279 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2280 if(FAILED(hr)) goto out;
2281 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2282 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2284 colorkey.dwColorSpaceLowValue = 0;
2285 colorkey.dwColorSpaceHighValue = 0;
2286 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2287 } else {
2288 /* Fill the surface with a white color to show that wined3d is there */
2289 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2292 out:
2293 if(dcb) {
2294 DeleteDC(dcb);
2296 if(hbm) {
2297 DeleteObject(hbm);
2299 return;
2302 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2303 unsigned int i;
2304 /* Under DirectX you can have texture stage operations even if no texture is
2305 bound, whereas opengl will only do texture operations when a valid texture is
2306 bound. We emulate this by creating dummy textures and binding them to each
2307 texture stage, but disable all stages by default. Hence if a stage is enabled
2308 then the default texture will kick in until replaced by a SetTexture call */
2309 ENTER_GL();
2311 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2312 /* The dummy texture does not have client storage backing */
2313 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2314 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2316 for (i = 0; i < GL_LIMITS(textures); i++) {
2317 GLubyte white = 255;
2319 /* Make appropriate texture active */
2320 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2321 checkGLcall("glActiveTextureARB");
2323 /* Generate an opengl texture name */
2324 glGenTextures(1, &This->dummyTextureName[i]);
2325 checkGLcall("glGenTextures");
2326 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2328 /* Generate a dummy 2d texture (not using 1d because they cause many
2329 * DRI drivers fall back to sw) */
2330 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2331 checkGLcall("glBindTexture");
2333 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2334 checkGLcall("glTexImage2D");
2336 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2337 /* Reenable because if supported it is enabled by default */
2338 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2339 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2342 LEAVE_GL();
2345 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2346 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2349 IWineD3DSwapChainImpl *swapchain = NULL;
2350 HRESULT hr;
2351 DWORD state;
2352 unsigned int i;
2354 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2356 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2357 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2359 /* TODO: Test if OpenGL is compiled in and loaded */
2361 TRACE("(%p) : Creating stateblock\n", This);
2362 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2363 hr = IWineD3DDevice_CreateStateBlock(iface,
2364 WINED3DSBT_INIT,
2365 (IWineD3DStateBlock **)&This->stateBlock,
2366 NULL);
2367 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2368 WARN("Failed to create stateblock\n");
2369 goto err_out;
2371 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2372 This->updateStateBlock = This->stateBlock;
2373 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2375 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2376 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2378 This->NumberOfPalettes = 1;
2379 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2380 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2381 ERR("Out of memory!\n");
2382 goto err_out;
2384 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2385 if(!This->palettes[0]) {
2386 ERR("Out of memory!\n");
2387 goto err_out;
2389 for (i = 0; i < 256; ++i) {
2390 This->palettes[0][i].peRed = 0xFF;
2391 This->palettes[0][i].peGreen = 0xFF;
2392 This->palettes[0][i].peBlue = 0xFF;
2393 This->palettes[0][i].peFlags = 0xFF;
2395 This->currentPalette = 0;
2397 /* Initialize the texture unit mapping to a 1:1 mapping */
2398 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2399 if (state < GL_LIMITS(fragment_samplers)) {
2400 This->texUnitMap[state] = state;
2401 This->rev_tex_unit_map[state] = state;
2402 } else {
2403 This->texUnitMap[state] = -1;
2404 This->rev_tex_unit_map[state] = -1;
2408 /* Setup the implicit swapchain */
2409 TRACE("Creating implicit swapchain\n");
2410 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2411 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2412 if (FAILED(hr))
2414 WARN("Failed to create implicit swapchain\n");
2415 goto err_out;
2418 This->NumberOfSwapChains = 1;
2419 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2420 if(!This->swapchains) {
2421 ERR("Out of memory!\n");
2422 goto err_out;
2424 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2426 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2427 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2428 This->render_targets[0] = swapchain->backBuffer[0];
2429 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2431 else {
2432 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2433 This->render_targets[0] = swapchain->frontBuffer;
2434 This->lastActiveRenderTarget = swapchain->frontBuffer;
2436 IWineD3DSurface_AddRef(This->render_targets[0]);
2437 This->activeContext = swapchain->context[0];
2438 This->lastThread = GetCurrentThreadId();
2440 /* Depth Stencil support */
2441 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2442 if (NULL != This->stencilBufferTarget) {
2443 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2446 hr = This->shader_backend->shader_alloc_private(iface);
2447 if(FAILED(hr)) {
2448 TRACE("Shader private data couldn't be allocated\n");
2449 goto err_out;
2451 hr = This->frag_pipe->alloc_private(iface);
2452 if(FAILED(hr)) {
2453 TRACE("Fragment pipeline private data couldn't be allocated\n");
2454 goto err_out;
2456 hr = This->blitter->alloc_private(iface);
2457 if(FAILED(hr)) {
2458 TRACE("Blitter private data couldn't be allocated\n");
2459 goto err_out;
2462 /* Set up some starting GL setup */
2464 /* Setup all the devices defaults */
2465 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2466 create_dummy_textures(This);
2468 ENTER_GL();
2470 /* Initialize the current view state */
2471 This->view_ident = 1;
2472 This->contexts[0]->last_was_rhw = 0;
2473 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2474 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2476 switch(wined3d_settings.offscreen_rendering_mode) {
2477 case ORM_FBO:
2478 case ORM_PBUFFER:
2479 This->offscreenBuffer = GL_BACK;
2480 break;
2482 case ORM_BACKBUFFER:
2484 if(This->activeContext->aux_buffers > 0) {
2485 TRACE("Using auxilliary buffer for offscreen rendering\n");
2486 This->offscreenBuffer = GL_AUX0;
2487 } else {
2488 TRACE("Using back buffer for offscreen rendering\n");
2489 This->offscreenBuffer = GL_BACK;
2494 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2495 LEAVE_GL();
2497 /* Clear the screen */
2498 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2499 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2500 0x00, 1.0, 0);
2502 This->d3d_initialized = TRUE;
2504 if(wined3d_settings.logo) {
2505 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2507 This->highest_dirty_ps_const = 0;
2508 This->highest_dirty_vs_const = 0;
2509 return WINED3D_OK;
2511 err_out:
2512 HeapFree(GetProcessHeap(), 0, This->render_targets);
2513 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2514 HeapFree(GetProcessHeap(), 0, This->swapchains);
2515 This->NumberOfSwapChains = 0;
2516 if(This->palettes) {
2517 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2518 HeapFree(GetProcessHeap(), 0, This->palettes);
2520 This->NumberOfPalettes = 0;
2521 if(swapchain) {
2522 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2524 if(This->stateBlock) {
2525 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2526 This->stateBlock = NULL;
2528 if (This->blit_priv) {
2529 This->blitter->free_private(iface);
2531 if (This->fragment_priv) {
2532 This->frag_pipe->free_private(iface);
2534 if (This->shader_priv) {
2535 This->shader_backend->shader_free_private(iface);
2537 return hr;
2540 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2541 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2544 IWineD3DSwapChainImpl *swapchain = NULL;
2545 HRESULT hr;
2547 /* Setup the implicit swapchain */
2548 TRACE("Creating implicit swapchain\n");
2549 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2550 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2551 if (FAILED(hr))
2553 WARN("Failed to create implicit swapchain\n");
2554 goto err_out;
2557 This->NumberOfSwapChains = 1;
2558 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2559 if(!This->swapchains) {
2560 ERR("Out of memory!\n");
2561 goto err_out;
2563 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2564 return WINED3D_OK;
2566 err_out:
2567 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2568 return hr;
2571 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2573 int sampler;
2574 UINT i;
2575 TRACE("(%p)\n", This);
2577 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2579 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2580 * it was created. Thus make sure a context is active for the glDelete* calls
2582 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2584 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2586 TRACE("Deleting high order patches\n");
2587 for(i = 0; i < PATCHMAP_SIZE; i++) {
2588 struct list *e1, *e2;
2589 struct WineD3DRectPatch *patch;
2590 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2591 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2592 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2596 /* Delete the palette conversion shader if it is around */
2597 if(This->paletteConversionShader) {
2598 ENTER_GL();
2599 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2600 LEAVE_GL();
2601 This->paletteConversionShader = 0;
2604 /* Delete the pbuffer context if there is any */
2605 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2607 /* Delete the mouse cursor texture */
2608 if(This->cursorTexture) {
2609 ENTER_GL();
2610 glDeleteTextures(1, &This->cursorTexture);
2611 LEAVE_GL();
2612 This->cursorTexture = 0;
2615 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2616 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2618 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2619 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2622 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2623 * private data, it might contain opengl pointers
2625 if(This->depth_blt_texture) {
2626 glDeleteTextures(1, &This->depth_blt_texture);
2627 This->depth_blt_texture = 0;
2629 if (This->depth_blt_rb) {
2630 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2631 This->depth_blt_rb = 0;
2632 This->depth_blt_rb_w = 0;
2633 This->depth_blt_rb_h = 0;
2636 /* Release the update stateblock */
2637 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2638 if(This->updateStateBlock != This->stateBlock)
2639 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2641 This->updateStateBlock = NULL;
2643 { /* because were not doing proper internal refcounts releasing the primary state block
2644 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2645 to set this->stateBlock = NULL; first */
2646 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2647 This->stateBlock = NULL;
2649 /* Release the stateblock */
2650 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2651 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2655 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2656 This->blitter->free_private(iface);
2657 This->frag_pipe->free_private(iface);
2658 This->shader_backend->shader_free_private(iface);
2660 /* Release the buffers (with sanity checks)*/
2661 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2662 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2663 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2664 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2666 This->stencilBufferTarget = NULL;
2668 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2669 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2670 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2672 TRACE("Setting rendertarget to NULL\n");
2673 This->render_targets[0] = NULL;
2675 if (This->auto_depth_stencil_buffer) {
2676 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2677 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2679 This->auto_depth_stencil_buffer = NULL;
2682 for(i=0; i < This->NumberOfSwapChains; i++) {
2683 TRACE("Releasing the implicit swapchain %d\n", i);
2684 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2685 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2689 HeapFree(GetProcessHeap(), 0, This->swapchains);
2690 This->swapchains = NULL;
2691 This->NumberOfSwapChains = 0;
2693 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2694 HeapFree(GetProcessHeap(), 0, This->palettes);
2695 This->palettes = NULL;
2696 This->NumberOfPalettes = 0;
2698 HeapFree(GetProcessHeap(), 0, This->render_targets);
2699 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2700 This->render_targets = NULL;
2701 This->draw_buffers = NULL;
2703 This->d3d_initialized = FALSE;
2704 return WINED3D_OK;
2707 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2709 unsigned int i;
2711 for(i=0; i < This->NumberOfSwapChains; i++) {
2712 TRACE("Releasing the implicit swapchain %d\n", i);
2713 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2714 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2718 HeapFree(GetProcessHeap(), 0, This->swapchains);
2719 This->swapchains = NULL;
2720 This->NumberOfSwapChains = 0;
2721 return WINED3D_OK;
2724 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2725 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2726 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2728 * There is no way to deactivate thread safety once it is enabled.
2730 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2733 /*For now just store the flag(needed in case of ddraw) */
2734 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2736 return;
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2740 const WINED3DDISPLAYMODE* pMode) {
2741 DEVMODEW devmode;
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 LONG ret;
2744 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2745 RECT clip_rc;
2747 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2749 /* Resize the screen even without a window:
2750 * The app could have unset it with SetCooperativeLevel, but not called
2751 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2752 * but we don't have any hwnd
2755 memset(&devmode, 0, sizeof(devmode));
2756 devmode.dmSize = sizeof(devmode);
2757 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2758 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2759 devmode.dmPelsWidth = pMode->Width;
2760 devmode.dmPelsHeight = pMode->Height;
2762 devmode.dmDisplayFrequency = pMode->RefreshRate;
2763 if (pMode->RefreshRate != 0) {
2764 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2767 /* Only change the mode if necessary */
2768 if( (This->ddraw_width == pMode->Width) &&
2769 (This->ddraw_height == pMode->Height) &&
2770 (This->ddraw_format == pMode->Format) &&
2771 (pMode->RefreshRate == 0) ) {
2772 return WINED3D_OK;
2775 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2776 if (ret != DISP_CHANGE_SUCCESSFUL) {
2777 if(devmode.dmDisplayFrequency != 0) {
2778 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2779 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2780 devmode.dmDisplayFrequency = 0;
2781 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2783 if(ret != DISP_CHANGE_SUCCESSFUL) {
2784 return WINED3DERR_NOTAVAILABLE;
2788 /* Store the new values */
2789 This->ddraw_width = pMode->Width;
2790 This->ddraw_height = pMode->Height;
2791 This->ddraw_format = pMode->Format;
2793 /* And finally clip mouse to our screen */
2794 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2795 ClipCursor(&clip_rc);
2797 return WINED3D_OK;
2800 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 *ppD3D= This->wineD3D;
2803 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2804 IWineD3D_AddRef(*ppD3D);
2805 return WINED3D_OK;
2808 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2812 (This->adapter->TextureRam/(1024*1024)),
2813 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2814 /* return simulated texture memory left */
2815 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2818 /*****
2819 * Get / Set Stream Source
2820 *****/
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2822 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2825 IWineD3DBuffer *oldSrc;
2827 if (StreamNumber >= MAX_STREAMS) {
2828 WARN("Stream out of range %d\n", StreamNumber);
2829 return WINED3DERR_INVALIDCALL;
2830 } else if(OffsetInBytes & 0x3) {
2831 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2832 return WINED3DERR_INVALIDCALL;
2835 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2836 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2838 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2840 if(oldSrc == pStreamData &&
2841 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2842 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2843 TRACE("Application is setting the old values over, nothing to do\n");
2844 return WINED3D_OK;
2847 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2848 if (pStreamData) {
2849 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2850 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2853 /* Handle recording of state blocks */
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2856 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2857 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2858 return WINED3D_OK;
2861 if (pStreamData != NULL) {
2862 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2863 IWineD3DBuffer_AddRef(pStreamData);
2865 if (oldSrc != NULL) {
2866 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2867 IWineD3DBuffer_Release(oldSrc);
2870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2872 return WINED3D_OK;
2875 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2876 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2880 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2881 This->stateBlock->streamSource[StreamNumber],
2882 This->stateBlock->streamOffset[StreamNumber],
2883 This->stateBlock->streamStride[StreamNumber]);
2885 if (StreamNumber >= MAX_STREAMS) {
2886 WARN("Stream out of range %d\n", StreamNumber);
2887 return WINED3DERR_INVALIDCALL;
2889 *pStream = This->stateBlock->streamSource[StreamNumber];
2890 *pStride = This->stateBlock->streamStride[StreamNumber];
2891 if (pOffset) {
2892 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2895 if (*pStream != NULL) {
2896 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2904 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2906 /* Verify input at least in d3d9 this is invalid*/
2907 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2908 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2909 return WINED3DERR_INVALIDCALL;
2911 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2912 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2913 return WINED3DERR_INVALIDCALL;
2915 if( Divider == 0 ){
2916 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2917 return WINED3DERR_INVALIDCALL;
2920 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2921 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2923 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2924 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2926 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2927 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2931 return WINED3D_OK;
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2938 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2940 TRACE("(%p) : returning %d\n", This, *Divider);
2942 return WINED3D_OK;
2945 /*****
2946 * Get / Set & Multiply Transform
2947 *****/
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 /* Most of this routine, comments included copied from ddraw tree initially: */
2952 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2954 /* Handle recording of state blocks */
2955 if (This->isRecordingState) {
2956 TRACE("Recording... not performing anything\n");
2957 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2958 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2959 return WINED3D_OK;
2963 * If the new matrix is the same as the current one,
2964 * we cut off any further processing. this seems to be a reasonable
2965 * optimization because as was noticed, some apps (warcraft3 for example)
2966 * tend towards setting the same matrix repeatedly for some reason.
2968 * From here on we assume that the new matrix is different, wherever it matters.
2970 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2971 TRACE("The app is setting the same matrix over again\n");
2972 return WINED3D_OK;
2973 } else {
2974 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2978 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2979 where ViewMat = Camera space, WorldMat = world space.
2981 In OpenGL, camera and world space is combined into GL_MODELVIEW
2982 matrix. The Projection matrix stay projection matrix.
2985 /* Capture the times we can just ignore the change for now */
2986 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2987 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2988 /* Handled by the state manager */
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2992 return WINED3D_OK;
2995 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2998 *pMatrix = This->stateBlock->transforms[State];
2999 return WINED3D_OK;
3002 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3003 const WINED3DMATRIX *mat = NULL;
3004 WINED3DMATRIX temp;
3006 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3007 * below means it will be recorded in a state block change, but it
3008 * works regardless where it is recorded.
3009 * If this is found to be wrong, change to StateBlock.
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3014 if (State <= HIGHEST_TRANSFORMSTATE)
3016 mat = &This->updateStateBlock->transforms[State];
3017 } else {
3018 FIXME("Unhandled transform state!!\n");
3021 multiply_matrix(&temp, mat, pMatrix);
3023 /* Apply change via set transform - will reapply to eg. lights this way */
3024 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3027 /*****
3028 * Get / Set Light
3029 *****/
3030 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3031 you can reference any indexes you want as long as that number max are enabled at any
3032 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3033 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3034 but when recording, just build a chain pretty much of commands to be replayed. */
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3037 float rho;
3038 PLIGHTINFOEL *object = NULL;
3039 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3040 struct list *e;
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3045 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3046 * the gl driver.
3048 if(!pLight) {
3049 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3050 return WINED3DERR_INVALIDCALL;
3053 switch(pLight->Type) {
3054 case WINED3DLIGHT_POINT:
3055 case WINED3DLIGHT_SPOT:
3056 case WINED3DLIGHT_PARALLELPOINT:
3057 case WINED3DLIGHT_GLSPOT:
3058 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3059 * most wanted
3061 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3062 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3063 return WINED3DERR_INVALIDCALL;
3065 break;
3067 case WINED3DLIGHT_DIRECTIONAL:
3068 /* Ignores attenuation */
3069 break;
3071 default:
3072 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3073 return WINED3DERR_INVALIDCALL;
3076 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3077 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3078 if(object->OriginalIndex == Index) break;
3079 object = NULL;
3082 if(!object) {
3083 TRACE("Adding new light\n");
3084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3085 if(!object) {
3086 ERR("Out of memory error when allocating a light\n");
3087 return E_OUTOFMEMORY;
3089 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3090 object->glIndex = -1;
3091 object->OriginalIndex = Index;
3092 object->changed = TRUE;
3095 /* Initialize the object */
3096 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,
3097 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3098 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3099 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3100 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3101 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3102 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3104 /* Save away the information */
3105 object->OriginalParms = *pLight;
3107 switch (pLight->Type) {
3108 case WINED3DLIGHT_POINT:
3109 /* Position */
3110 object->lightPosn[0] = pLight->Position.x;
3111 object->lightPosn[1] = pLight->Position.y;
3112 object->lightPosn[2] = pLight->Position.z;
3113 object->lightPosn[3] = 1.0f;
3114 object->cutoff = 180.0f;
3115 /* FIXME: Range */
3116 break;
3118 case WINED3DLIGHT_DIRECTIONAL:
3119 /* Direction */
3120 object->lightPosn[0] = -pLight->Direction.x;
3121 object->lightPosn[1] = -pLight->Direction.y;
3122 object->lightPosn[2] = -pLight->Direction.z;
3123 object->lightPosn[3] = 0.0;
3124 object->exponent = 0.0f;
3125 object->cutoff = 180.0f;
3126 break;
3128 case WINED3DLIGHT_SPOT:
3129 /* Position */
3130 object->lightPosn[0] = pLight->Position.x;
3131 object->lightPosn[1] = pLight->Position.y;
3132 object->lightPosn[2] = pLight->Position.z;
3133 object->lightPosn[3] = 1.0;
3135 /* Direction */
3136 object->lightDirn[0] = pLight->Direction.x;
3137 object->lightDirn[1] = pLight->Direction.y;
3138 object->lightDirn[2] = pLight->Direction.z;
3139 object->lightDirn[3] = 1.0;
3142 * opengl-ish and d3d-ish spot lights use too different models for the
3143 * light "intensity" as a function of the angle towards the main light direction,
3144 * so we only can approximate very roughly.
3145 * however spot lights are rather rarely used in games (if ever used at all).
3146 * furthermore if still used, probably nobody pays attention to such details.
3148 if (pLight->Falloff == 0) {
3149 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3150 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3151 * will always be 1.0 for both of them, and we don't have to care for the
3152 * rest of the rather complex calculation
3154 object->exponent = 0;
3155 } else {
3156 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3157 if (rho < 0.0001) rho = 0.0001f;
3158 object->exponent = -0.3/log(cos(rho/2));
3160 if (object->exponent > 128.0) {
3161 object->exponent = 128.0;
3163 object->cutoff = pLight->Phi*90/M_PI;
3165 /* FIXME: Range */
3166 break;
3168 default:
3169 FIXME("Unrecognized light type %d\n", pLight->Type);
3172 /* Update the live definitions if the light is currently assigned a glIndex */
3173 if (object->glIndex != -1 && !This->isRecordingState) {
3174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3176 return WINED3D_OK;
3179 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3180 PLIGHTINFOEL *lightInfo = NULL;
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3183 struct list *e;
3184 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3186 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3187 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3188 if(lightInfo->OriginalIndex == Index) break;
3189 lightInfo = NULL;
3192 if (lightInfo == NULL) {
3193 TRACE("Light information requested but light not defined\n");
3194 return WINED3DERR_INVALIDCALL;
3197 *pLight = lightInfo->OriginalParms;
3198 return WINED3D_OK;
3201 /*****
3202 * Get / Set Light Enable
3203 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3204 *****/
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3206 PLIGHTINFOEL *lightInfo = NULL;
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3209 struct list *e;
3210 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3212 /* Tests show true = 128...not clear why */
3213 Enable = Enable? 128: 0;
3215 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3216 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3217 if(lightInfo->OriginalIndex == Index) break;
3218 lightInfo = NULL;
3220 TRACE("Found light: %p\n", lightInfo);
3222 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3223 if (lightInfo == NULL) {
3225 TRACE("Light enabled requested but light not defined, so defining one!\n");
3226 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3228 /* Search for it again! Should be fairly quick as near head of list */
3229 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3230 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3231 if(lightInfo->OriginalIndex == Index) break;
3232 lightInfo = NULL;
3234 if (lightInfo == NULL) {
3235 FIXME("Adding default lights has failed dismally\n");
3236 return WINED3DERR_INVALIDCALL;
3240 lightInfo->enabledChanged = TRUE;
3241 if(!Enable) {
3242 if(lightInfo->glIndex != -1) {
3243 if(!This->isRecordingState) {
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3247 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3248 lightInfo->glIndex = -1;
3249 } else {
3250 TRACE("Light already disabled, nothing to do\n");
3252 lightInfo->enabled = FALSE;
3253 } else {
3254 lightInfo->enabled = TRUE;
3255 if (lightInfo->glIndex != -1) {
3256 /* nop */
3257 TRACE("Nothing to do as light was enabled\n");
3258 } else {
3259 int i;
3260 /* Find a free gl light */
3261 for(i = 0; i < This->maxConcurrentLights; i++) {
3262 if(This->updateStateBlock->activeLights[i] == NULL) {
3263 This->updateStateBlock->activeLights[i] = lightInfo;
3264 lightInfo->glIndex = i;
3265 break;
3268 if(lightInfo->glIndex == -1) {
3269 /* Our tests show that Windows returns D3D_OK in this situation, even with
3270 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3271 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3272 * as well for those lights.
3274 * TODO: Test how this affects rendering
3276 WARN("Too many concurrently active lights\n");
3277 return WINED3D_OK;
3280 /* i == lightInfo->glIndex */
3281 if(!This->isRecordingState) {
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3287 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3292 PLIGHTINFOEL *lightInfo = NULL;
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 struct list *e;
3295 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3296 TRACE("(%p) : for idx(%d)\n", This, Index);
3298 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3299 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3300 if(lightInfo->OriginalIndex == Index) break;
3301 lightInfo = NULL;
3304 if (lightInfo == NULL) {
3305 TRACE("Light enabled state requested but light not defined\n");
3306 return WINED3DERR_INVALIDCALL;
3308 /* true is 128 according to SetLightEnable */
3309 *pEnable = lightInfo->enabled ? 128 : 0;
3310 return WINED3D_OK;
3313 /*****
3314 * Get / Set Clip Planes
3315 *****/
3316 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3320 /* Validate Index */
3321 if (Index >= GL_LIMITS(clipplanes)) {
3322 TRACE("Application has requested clipplane this device doesn't support\n");
3323 return WINED3DERR_INVALIDCALL;
3326 This->updateStateBlock->changed.clipplane |= 1 << Index;
3328 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3329 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3330 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3331 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3332 TRACE("Application is setting old values over, nothing to do\n");
3333 return WINED3D_OK;
3336 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3337 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3338 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3339 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3341 /* Handle recording of state blocks */
3342 if (This->isRecordingState) {
3343 TRACE("Recording... not performing anything\n");
3344 return WINED3D_OK;
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3349 return WINED3D_OK;
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 TRACE("(%p) : for idx %d\n", This, Index);
3356 /* Validate Index */
3357 if (Index >= GL_LIMITS(clipplanes)) {
3358 TRACE("Application has requested clipplane this device doesn't support\n");
3359 return WINED3DERR_INVALIDCALL;
3362 pPlane[0] = This->stateBlock->clipplane[Index][0];
3363 pPlane[1] = This->stateBlock->clipplane[Index][1];
3364 pPlane[2] = This->stateBlock->clipplane[Index][2];
3365 pPlane[3] = This->stateBlock->clipplane[Index][3];
3366 return WINED3D_OK;
3369 /*****
3370 * Get / Set Clip Plane Status
3371 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3372 *****/
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 FIXME("(%p) : stub\n", This);
3376 if (NULL == pClipStatus) {
3377 return WINED3DERR_INVALIDCALL;
3379 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3380 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3381 return WINED3D_OK;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 FIXME("(%p) : stub\n", This);
3387 if (NULL == pClipStatus) {
3388 return WINED3DERR_INVALIDCALL;
3390 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3391 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3392 return WINED3D_OK;
3395 /*****
3396 * Get / Set Material
3397 *****/
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 This->updateStateBlock->changed.material = TRUE;
3402 This->updateStateBlock->material = *pMaterial;
3404 /* Handle recording of state blocks */
3405 if (This->isRecordingState) {
3406 TRACE("Recording... not performing anything\n");
3407 return WINED3D_OK;
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3411 return WINED3D_OK;
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 *pMaterial = This->updateStateBlock->material;
3417 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3418 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3419 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3420 pMaterial->Ambient.b, pMaterial->Ambient.a);
3421 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3422 pMaterial->Specular.b, pMaterial->Specular.a);
3423 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3424 pMaterial->Emissive.b, pMaterial->Emissive.a);
3425 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3427 return WINED3D_OK;
3430 /*****
3431 * Get / Set Indices
3432 *****/
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 IWineD3DIndexBuffer *oldIdxs;
3437 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3438 oldIdxs = This->updateStateBlock->pIndexData;
3440 This->updateStateBlock->changed.indices = TRUE;
3441 This->updateStateBlock->pIndexData = pIndexData;
3443 /* Handle recording of state blocks */
3444 if (This->isRecordingState) {
3445 TRACE("Recording... not performing anything\n");
3446 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3447 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3448 return WINED3D_OK;
3451 if(oldIdxs != pIndexData) {
3452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3453 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3454 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3456 return WINED3D_OK;
3459 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 *ppIndexData = This->stateBlock->pIndexData;
3464 /* up ref count on ppindexdata */
3465 if (*ppIndexData) {
3466 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3467 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3468 }else{
3469 TRACE("(%p) No index data set\n", This);
3471 TRACE("Returning %p\n", *ppIndexData);
3473 return WINED3D_OK;
3476 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 TRACE("(%p)->(%d)\n", This, BaseIndex);
3481 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3482 TRACE("Application is setting the old value over, nothing to do\n");
3483 return WINED3D_OK;
3486 This->updateStateBlock->baseVertexIndex = BaseIndex;
3488 if (This->isRecordingState) {
3489 TRACE("Recording... not performing anything\n");
3490 return WINED3D_OK;
3492 /* The base vertex index affects the stream sources */
3493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3494 return WINED3D_OK;
3497 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 TRACE("(%p) : base_index %p\n", This, base_index);
3501 *base_index = This->stateBlock->baseVertexIndex;
3503 TRACE("Returning %u\n", *base_index);
3505 return WINED3D_OK;
3508 /*****
3509 * Get / Set Viewports
3510 *****/
3511 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 TRACE("(%p)\n", This);
3515 This->updateStateBlock->changed.viewport = TRUE;
3516 This->updateStateBlock->viewport = *pViewport;
3518 /* Handle recording of state blocks */
3519 if (This->isRecordingState) {
3520 TRACE("Recording... not performing anything\n");
3521 return WINED3D_OK;
3524 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3525 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3528 return WINED3D_OK;
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 TRACE("(%p)\n", This);
3535 *pViewport = This->stateBlock->viewport;
3536 return WINED3D_OK;
3539 /*****
3540 * Get / Set Render States
3541 * TODO: Verify against dx9 definitions
3542 *****/
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 DWORD oldValue = This->stateBlock->renderState[State];
3548 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3550 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3551 This->updateStateBlock->renderState[State] = Value;
3553 /* Handle recording of state blocks */
3554 if (This->isRecordingState) {
3555 TRACE("Recording... not performing anything\n");
3556 return WINED3D_OK;
3559 /* Compared here and not before the assignment to allow proper stateblock recording */
3560 if(Value == oldValue) {
3561 TRACE("Application is setting the old value over, nothing to do\n");
3562 } else {
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3566 return WINED3D_OK;
3569 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3572 *pValue = This->stateBlock->renderState[State];
3573 return WINED3D_OK;
3576 /*****
3577 * Get / Set Sampler States
3578 * TODO: Verify against dx9 definitions
3579 *****/
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 DWORD oldValue;
3585 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3586 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3588 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3589 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3592 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3593 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3594 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3597 * SetSampler is designed to allow for more than the standard up to 8 textures
3598 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3599 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3601 * http://developer.nvidia.com/object/General_FAQ.html#t6
3603 * There are two new settings for GForce
3604 * the sampler one:
3605 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3606 * and the texture one:
3607 * GL_MAX_TEXTURE_COORDS_ARB.
3608 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3609 ******************/
3611 oldValue = This->stateBlock->samplerState[Sampler][Type];
3612 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3613 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3615 /* Handle recording of state blocks */
3616 if (This->isRecordingState) {
3617 TRACE("Recording... not performing anything\n");
3618 return WINED3D_OK;
3621 if(oldValue == Value) {
3622 TRACE("Application is setting the old value over, nothing to do\n");
3623 return WINED3D_OK;
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3628 return WINED3D_OK;
3631 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3634 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3635 This, Sampler, debug_d3dsamplerstate(Type), Type);
3637 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3638 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3641 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3642 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3643 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3645 *Value = This->stateBlock->samplerState[Sampler][Type];
3646 TRACE("(%p) : Returning %#x\n", This, *Value);
3648 return WINED3D_OK;
3651 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654 This->updateStateBlock->changed.scissorRect = TRUE;
3655 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3656 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3657 return WINED3D_OK;
3659 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3661 if(This->isRecordingState) {
3662 TRACE("Recording... not performing anything\n");
3663 return WINED3D_OK;
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3668 return WINED3D_OK;
3671 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3674 *pRect = This->updateStateBlock->scissorRect;
3675 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3676 return WINED3D_OK;
3679 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3681 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3683 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3685 This->updateStateBlock->vertexDecl = pDecl;
3686 This->updateStateBlock->changed.vertexDecl = TRUE;
3688 if (This->isRecordingState) {
3689 TRACE("Recording... not performing anything\n");
3690 return WINED3D_OK;
3691 } else if(pDecl == oldDecl) {
3692 /* Checked after the assignment to allow proper stateblock recording */
3693 TRACE("Application is setting the old declaration over, nothing to do\n");
3694 return WINED3D_OK;
3697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3698 return WINED3D_OK;
3701 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3706 *ppDecl = This->stateBlock->vertexDecl;
3707 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3708 return WINED3D_OK;
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3713 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3715 This->updateStateBlock->vertexShader = pShader;
3716 This->updateStateBlock->changed.vertexShader = TRUE;
3718 if (This->isRecordingState) {
3719 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3720 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3721 TRACE("Recording... not performing anything\n");
3722 return WINED3D_OK;
3723 } else if(oldShader == pShader) {
3724 /* Checked here to allow proper stateblock recording */
3725 TRACE("App is setting the old shader over, nothing to do\n");
3726 return WINED3D_OK;
3729 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3730 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3731 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3735 return WINED3D_OK;
3738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 if (NULL == ppShader) {
3742 return WINED3DERR_INVALIDCALL;
3744 *ppShader = This->stateBlock->vertexShader;
3745 if( NULL != *ppShader)
3746 IWineD3DVertexShader_AddRef(*ppShader);
3748 TRACE("(%p) : returning %p\n", This, *ppShader);
3749 return WINED3D_OK;
3752 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3753 IWineD3DDevice *iface,
3754 UINT start,
3755 CONST BOOL *srcData,
3756 UINT count) {
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 int i, cnt = min(count, MAX_CONST_B - start);
3761 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3762 iface, srcData, start, count);
3764 if (srcData == NULL || cnt < 0)
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3768 for (i = 0; i < cnt; i++)
3769 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3771 for (i = start; i < cnt + start; ++i) {
3772 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3775 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3777 return WINED3D_OK;
3780 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3781 IWineD3DDevice *iface,
3782 UINT start,
3783 BOOL *dstData,
3784 UINT count) {
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int cnt = min(count, MAX_CONST_B - start);
3789 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3790 iface, dstData, start, count);
3792 if (dstData == NULL || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3796 return WINED3D_OK;
3799 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3800 IWineD3DDevice *iface,
3801 UINT start,
3802 CONST int *srcData,
3803 UINT count) {
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 int i, cnt = min(count, MAX_CONST_I - start);
3808 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3809 iface, srcData, start, count);
3811 if (srcData == NULL || cnt < 0)
3812 return WINED3DERR_INVALIDCALL;
3814 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3815 for (i = 0; i < cnt; i++)
3816 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3817 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3819 for (i = start; i < cnt + start; ++i) {
3820 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3823 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3825 return WINED3D_OK;
3828 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3829 IWineD3DDevice *iface,
3830 UINT start,
3831 int *dstData,
3832 UINT count) {
3834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3835 int cnt = min(count, MAX_CONST_I - start);
3837 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3838 iface, dstData, start, count);
3840 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3841 return WINED3DERR_INVALIDCALL;
3843 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3844 return WINED3D_OK;
3847 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3848 IWineD3DDevice *iface,
3849 UINT start,
3850 CONST float *srcData,
3851 UINT count) {
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 UINT i;
3856 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3857 iface, srcData, start, count);
3859 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3860 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3861 return WINED3DERR_INVALIDCALL;
3863 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3864 if(TRACE_ON(d3d)) {
3865 for (i = 0; i < count; i++)
3866 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3867 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3870 if (!This->isRecordingState)
3872 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3876 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3877 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3879 return WINED3D_OK;
3882 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3883 IWineD3DDevice *iface,
3884 UINT start,
3885 float *dstData,
3886 UINT count) {
3888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3889 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3891 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3892 iface, dstData, start, count);
3894 if (dstData == NULL || cnt < 0)
3895 return WINED3DERR_INVALIDCALL;
3897 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3898 return WINED3D_OK;
3901 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3902 DWORD i;
3903 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3909 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3910 int i = This->rev_tex_unit_map[unit];
3911 int j = This->texUnitMap[stage];
3913 This->texUnitMap[stage] = unit;
3914 if (i != -1 && i != stage) {
3915 This->texUnitMap[i] = -1;
3918 This->rev_tex_unit_map[unit] = stage;
3919 if (j != -1 && j != unit) {
3920 This->rev_tex_unit_map[j] = -1;
3924 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3925 int i;
3927 This->fixed_function_usage_map = 0;
3928 for (i = 0; i < MAX_TEXTURES; ++i) {
3929 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3930 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3931 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3932 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3933 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3934 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3935 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3936 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3938 if (color_op == WINED3DTOP_DISABLE) {
3939 /* Not used, and disable higher stages */
3940 break;
3943 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3944 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3945 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3946 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3947 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3948 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3949 This->fixed_function_usage_map |= (1 << i);
3952 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3953 This->fixed_function_usage_map |= (1 << (i + 1));
3958 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3959 int i, tex;
3960 WORD ffu_map;
3962 device_update_fixed_function_usage_map(This);
3963 ffu_map = This->fixed_function_usage_map;
3965 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3966 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3967 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3969 if (!(ffu_map & 1)) continue;
3971 if (This->texUnitMap[i] != i) {
3972 device_map_stage(This, i, i);
3973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3974 markTextureStagesDirty(This, i);
3977 return;
3980 /* Now work out the mapping */
3981 tex = 0;
3982 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3984 if (!(ffu_map & 1)) continue;
3986 if (This->texUnitMap[i] != tex) {
3987 device_map_stage(This, i, tex);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3989 markTextureStagesDirty(This, i);
3992 ++tex;
3996 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3997 const DWORD *sampler_tokens =
3998 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3999 int i;
4001 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4002 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4003 device_map_stage(This, i, i);
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4005 if (i < MAX_TEXTURES) {
4006 markTextureStagesDirty(This, i);
4012 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4013 const DWORD *vshader_sampler_tokens, int unit)
4015 int current_mapping = This->rev_tex_unit_map[unit];
4017 if (current_mapping == -1) {
4018 /* Not currently used */
4019 return TRUE;
4022 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4023 /* Used by a fragment sampler */
4025 if (!pshader_sampler_tokens) {
4026 /* No pixel shader, check fixed function */
4027 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4030 /* Pixel shader, check the shader's sampler map */
4031 return !pshader_sampler_tokens[current_mapping];
4034 /* Used by a vertex sampler */
4035 return !vshader_sampler_tokens[current_mapping];
4038 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4039 const DWORD *vshader_sampler_tokens =
4040 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4041 const DWORD *pshader_sampler_tokens = NULL;
4042 int start = GL_LIMITS(combined_samplers) - 1;
4043 int i;
4045 if (ps) {
4046 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4048 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4049 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4050 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4053 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4054 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4055 if (vshader_sampler_tokens[i]) {
4056 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4058 /* Already mapped somewhere */
4059 continue;
4062 while (start >= 0) {
4063 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4064 device_map_stage(This, vsampler_idx, start);
4065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4067 --start;
4068 break;
4071 --start;
4077 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4078 BOOL vs = use_vs(This->stateBlock);
4079 BOOL ps = use_ps(This->stateBlock);
4081 * Rules are:
4082 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4083 * that would be really messy and require shader recompilation
4084 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4085 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4087 if (ps) {
4088 device_map_psamplers(This);
4089 } else {
4090 device_map_fixed_function_samplers(This);
4093 if (vs) {
4094 device_map_vsamplers(This, ps);
4098 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4100 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4101 This->updateStateBlock->pixelShader = pShader;
4102 This->updateStateBlock->changed.pixelShader = TRUE;
4104 /* Handle recording of state blocks */
4105 if (This->isRecordingState) {
4106 TRACE("Recording... not performing anything\n");
4109 if (This->isRecordingState) {
4110 TRACE("Recording... not performing anything\n");
4111 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4112 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4113 return WINED3D_OK;
4116 if(pShader == oldShader) {
4117 TRACE("App is setting the old pixel shader over, nothing to do\n");
4118 return WINED3D_OK;
4121 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4122 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4124 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4127 return WINED3D_OK;
4130 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 if (NULL == ppShader) {
4134 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4135 return WINED3DERR_INVALIDCALL;
4138 *ppShader = This->stateBlock->pixelShader;
4139 if (NULL != *ppShader) {
4140 IWineD3DPixelShader_AddRef(*ppShader);
4142 TRACE("(%p) : returning %p\n", This, *ppShader);
4143 return WINED3D_OK;
4146 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4147 IWineD3DDevice *iface,
4148 UINT start,
4149 CONST BOOL *srcData,
4150 UINT count) {
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 int i, cnt = min(count, MAX_CONST_B - start);
4155 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4156 iface, srcData, start, count);
4158 if (srcData == NULL || cnt < 0)
4159 return WINED3DERR_INVALIDCALL;
4161 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4162 for (i = 0; i < cnt; i++)
4163 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4165 for (i = start; i < cnt + start; ++i) {
4166 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4169 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4171 return WINED3D_OK;
4174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4175 IWineD3DDevice *iface,
4176 UINT start,
4177 BOOL *dstData,
4178 UINT count) {
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 int cnt = min(count, MAX_CONST_B - start);
4183 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4184 iface, dstData, start, count);
4186 if (dstData == NULL || cnt < 0)
4187 return WINED3DERR_INVALIDCALL;
4189 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4190 return WINED3D_OK;
4193 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4194 IWineD3DDevice *iface,
4195 UINT start,
4196 CONST int *srcData,
4197 UINT count) {
4199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4200 int i, cnt = min(count, MAX_CONST_I - start);
4202 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4203 iface, srcData, start, count);
4205 if (srcData == NULL || cnt < 0)
4206 return WINED3DERR_INVALIDCALL;
4208 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4209 for (i = 0; i < cnt; i++)
4210 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4211 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4213 for (i = start; i < cnt + start; ++i) {
4214 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4217 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4219 return WINED3D_OK;
4222 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4223 IWineD3DDevice *iface,
4224 UINT start,
4225 int *dstData,
4226 UINT count) {
4228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4229 int cnt = min(count, MAX_CONST_I - start);
4231 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4232 iface, dstData, start, count);
4234 if (dstData == NULL || cnt < 0)
4235 return WINED3DERR_INVALIDCALL;
4237 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4238 return WINED3D_OK;
4241 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4242 IWineD3DDevice *iface,
4243 UINT start,
4244 CONST float *srcData,
4245 UINT count) {
4247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4248 UINT i;
4250 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4251 iface, srcData, start, count);
4253 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4254 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4255 return WINED3DERR_INVALIDCALL;
4257 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4258 if(TRACE_ON(d3d)) {
4259 for (i = 0; i < count; i++)
4260 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4261 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4264 if (!This->isRecordingState)
4266 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4270 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4271 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4273 return WINED3D_OK;
4276 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4277 IWineD3DDevice *iface,
4278 UINT start,
4279 float *dstData,
4280 UINT count) {
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4285 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4286 iface, dstData, start, count);
4288 if (dstData == NULL || cnt < 0)
4289 return WINED3DERR_INVALIDCALL;
4291 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4292 return WINED3D_OK;
4295 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4296 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4297 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4299 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4300 unsigned int i;
4301 DWORD DestFVF = dest->fvf;
4302 WINED3DVIEWPORT vp;
4303 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4304 BOOL doClip;
4305 DWORD numTextures;
4307 if (lpStrideData->u.s.normal.lpData) {
4308 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4311 if (lpStrideData->u.s.position.lpData == NULL) {
4312 ERR("Source has no position mask\n");
4313 return WINED3DERR_INVALIDCALL;
4316 /* We might access VBOs from this code, so hold the lock */
4317 ENTER_GL();
4319 if (dest->resource.allocatedMemory == NULL) {
4320 /* This may happen if we do direct locking into a vbo. Unlikely,
4321 * but theoretically possible(ddraw processvertices test)
4323 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4324 if(!dest->resource.allocatedMemory) {
4325 LEAVE_GL();
4326 ERR("Out of memory\n");
4327 return E_OUTOFMEMORY;
4329 if (dest->buffer_object)
4331 const void *src;
4332 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4333 checkGLcall("glBindBufferARB");
4334 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4335 if(src) {
4336 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4338 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4339 checkGLcall("glUnmapBufferARB");
4343 /* Get a pointer into the destination vbo(create one if none exists) and
4344 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4346 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4348 dest->flags |= WINED3D_BUFFER_CREATEBO;
4349 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4352 if (dest->buffer_object)
4354 unsigned char extrabytes = 0;
4355 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4356 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4357 * this may write 4 extra bytes beyond the area that should be written
4359 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4360 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4361 if(!dest_conv_addr) {
4362 ERR("Out of memory\n");
4363 /* Continue without storing converted vertices */
4365 dest_conv = dest_conv_addr;
4368 /* Should I clip?
4369 * a) WINED3DRS_CLIPPING is enabled
4370 * b) WINED3DVOP_CLIP is passed
4372 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4373 static BOOL warned = FALSE;
4375 * The clipping code is not quite correct. Some things need
4376 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4377 * so disable clipping for now.
4378 * (The graphics in Half-Life are broken, and my processvertices
4379 * test crashes with IDirect3DDevice3)
4380 doClip = TRUE;
4382 doClip = FALSE;
4383 if(!warned) {
4384 warned = TRUE;
4385 FIXME("Clipping is broken and disabled for now\n");
4387 } else doClip = FALSE;
4388 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4390 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4391 WINED3DTS_VIEW,
4392 &view_mat);
4393 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4394 WINED3DTS_PROJECTION,
4395 &proj_mat);
4396 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4397 WINED3DTS_WORLDMATRIX(0),
4398 &world_mat);
4400 TRACE("View mat:\n");
4401 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);
4402 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);
4403 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);
4404 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);
4406 TRACE("Proj mat:\n");
4407 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);
4408 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);
4409 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);
4410 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);
4412 TRACE("World mat:\n");
4413 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);
4414 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);
4415 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);
4416 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);
4418 /* Get the viewport */
4419 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4420 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4421 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4423 multiply_matrix(&mat,&view_mat,&world_mat);
4424 multiply_matrix(&mat,&proj_mat,&mat);
4426 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4428 for (i = 0; i < dwCount; i+= 1) {
4429 unsigned int tex_index;
4431 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4432 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4433 /* The position first */
4434 const float *p =
4435 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4436 float x, y, z, rhw;
4437 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4439 /* Multiplication with world, view and projection matrix */
4440 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
4441 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
4442 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
4443 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
4445 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4447 /* WARNING: The following things are taken from d3d7 and were not yet checked
4448 * against d3d8 or d3d9!
4451 /* Clipping conditions: From msdn
4453 * A vertex is clipped if it does not match the following requirements
4454 * -rhw < x <= rhw
4455 * -rhw < y <= rhw
4456 * 0 < z <= rhw
4457 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4459 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4460 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4464 if( !doClip ||
4465 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4466 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4467 ( rhw > eps ) ) ) {
4469 /* "Normal" viewport transformation (not clipped)
4470 * 1) The values are divided by rhw
4471 * 2) The y axis is negative, so multiply it with -1
4472 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4473 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4474 * 4) Multiply x with Width/2 and add Width/2
4475 * 5) The same for the height
4476 * 6) Add the viewpoint X and Y to the 2D coordinates and
4477 * The minimum Z value to z
4478 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4480 * Well, basically it's simply a linear transformation into viewport
4481 * coordinates
4484 x /= rhw;
4485 y /= rhw;
4486 z /= rhw;
4488 y *= -1;
4490 x *= vp.Width / 2;
4491 y *= vp.Height / 2;
4492 z *= vp.MaxZ - vp.MinZ;
4494 x += vp.Width / 2 + vp.X;
4495 y += vp.Height / 2 + vp.Y;
4496 z += vp.MinZ;
4498 rhw = 1 / rhw;
4499 } else {
4500 /* That vertex got clipped
4501 * Contrary to OpenGL it is not dropped completely, it just
4502 * undergoes a different calculation.
4504 TRACE("Vertex got clipped\n");
4505 x += rhw;
4506 y += rhw;
4508 x /= 2;
4509 y /= 2;
4511 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4512 * outside of the main vertex buffer memory. That needs some more
4513 * investigation...
4517 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4520 ( (float *) dest_ptr)[0] = x;
4521 ( (float *) dest_ptr)[1] = y;
4522 ( (float *) dest_ptr)[2] = z;
4523 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4525 dest_ptr += 3 * sizeof(float);
4527 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4528 dest_ptr += sizeof(float);
4531 if(dest_conv) {
4532 float w = 1 / rhw;
4533 ( (float *) dest_conv)[0] = x * w;
4534 ( (float *) dest_conv)[1] = y * w;
4535 ( (float *) dest_conv)[2] = z * w;
4536 ( (float *) dest_conv)[3] = w;
4538 dest_conv += 3 * sizeof(float);
4540 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4541 dest_conv += sizeof(float);
4545 if (DestFVF & WINED3DFVF_PSIZE) {
4546 dest_ptr += sizeof(DWORD);
4547 if(dest_conv) dest_conv += sizeof(DWORD);
4549 if (DestFVF & WINED3DFVF_NORMAL) {
4550 const float *normal =
4551 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4552 /* AFAIK this should go into the lighting information */
4553 FIXME("Didn't expect the destination to have a normal\n");
4554 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4555 if(dest_conv) {
4556 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4560 if (DestFVF & WINED3DFVF_DIFFUSE) {
4561 const DWORD *color_d =
4562 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4563 if(!color_d) {
4564 static BOOL warned = FALSE;
4566 if(!warned) {
4567 ERR("No diffuse color in source, but destination has one\n");
4568 warned = TRUE;
4571 *( (DWORD *) dest_ptr) = 0xffffffff;
4572 dest_ptr += sizeof(DWORD);
4574 if(dest_conv) {
4575 *( (DWORD *) dest_conv) = 0xffffffff;
4576 dest_conv += sizeof(DWORD);
4579 else {
4580 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4581 if(dest_conv) {
4582 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4583 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4584 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4585 dest_conv += sizeof(DWORD);
4590 if (DestFVF & WINED3DFVF_SPECULAR) {
4591 /* What's the color value in the feedback buffer? */
4592 const DWORD *color_s =
4593 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4594 if(!color_s) {
4595 static BOOL warned = FALSE;
4597 if(!warned) {
4598 ERR("No specular color in source, but destination has one\n");
4599 warned = TRUE;
4602 *( (DWORD *) dest_ptr) = 0xFF000000;
4603 dest_ptr += sizeof(DWORD);
4605 if(dest_conv) {
4606 *( (DWORD *) dest_conv) = 0xFF000000;
4607 dest_conv += sizeof(DWORD);
4610 else {
4611 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4612 if(dest_conv) {
4613 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4614 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4615 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4616 dest_conv += sizeof(DWORD);
4621 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4622 const float *tex_coord =
4623 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4624 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4625 if(!tex_coord) {
4626 ERR("No source texture, but destination requests one\n");
4627 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4628 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4630 else {
4631 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4632 if(dest_conv) {
4633 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4639 if(dest_conv) {
4640 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4641 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4642 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4643 dwCount * get_flexible_vertex_size(DestFVF),
4644 dest_conv_addr));
4645 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4646 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4649 LEAVE_GL();
4651 return WINED3D_OK;
4653 #undef copy_and_next
4655 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4656 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 WineDirect3DVertexStridedData strided;
4660 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4661 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4663 if(pVertexDecl) {
4664 ERR("Output vertex declaration not implemented yet\n");
4667 /* Need any context to write to the vbo. */
4668 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4670 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4671 * control the streamIsUP flag, thus restore it afterwards.
4673 This->stateBlock->streamIsUP = FALSE;
4674 memset(&strided, 0, sizeof(strided));
4675 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4676 This->stateBlock->streamIsUP = streamWasUP;
4678 if(vbo || SrcStartIndex) {
4679 unsigned int i;
4680 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4681 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4683 * Also get the start index in, but only loop over all elements if there's something to add at all.
4685 #define FIXSRC(type) \
4686 if(strided.u.s.type.VBO) { \
4687 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4688 strided.u.s.type.VBO = 0; \
4689 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4690 ENTER_GL(); \
4691 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4692 vb->buffer_object = 0; \
4693 LEAVE_GL(); \
4695 if(strided.u.s.type.lpData) { \
4696 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4698 FIXSRC(position);
4699 FIXSRC(blendWeights);
4700 FIXSRC(blendMatrixIndices);
4701 FIXSRC(normal);
4702 FIXSRC(pSize);
4703 FIXSRC(diffuse);
4704 FIXSRC(specular);
4705 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4706 FIXSRC(texCoords[i]);
4708 FIXSRC(position2);
4709 FIXSRC(normal2);
4710 FIXSRC(tangent);
4711 FIXSRC(binormal);
4712 FIXSRC(tessFactor);
4713 FIXSRC(fog);
4714 FIXSRC(depth);
4715 FIXSRC(sample);
4716 #undef FIXSRC
4719 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4720 (struct wined3d_buffer *)pDestBuffer, Flags);
4723 /*****
4724 * Get / Set Texture Stage States
4725 * TODO: Verify against dx9 definitions
4726 *****/
4727 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4731 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4733 if (Stage >= MAX_TEXTURES) {
4734 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4735 return WINED3D_OK;
4738 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4739 This->updateStateBlock->textureState[Stage][Type] = Value;
4741 if (This->isRecordingState) {
4742 TRACE("Recording... not performing anything\n");
4743 return WINED3D_OK;
4746 /* Checked after the assignments to allow proper stateblock recording */
4747 if(oldValue == Value) {
4748 TRACE("App is setting the old value over, nothing to do\n");
4749 return WINED3D_OK;
4752 if(Stage > This->stateBlock->lowest_disabled_stage &&
4753 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4754 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4755 * Changes in other states are important on disabled stages too
4757 return WINED3D_OK;
4760 if(Type == WINED3DTSS_COLOROP) {
4761 int i;
4763 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4764 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4765 * they have to be disabled
4767 * The current stage is dirtified below.
4769 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4770 TRACE("Additionally dirtifying stage %d\n", i);
4771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4773 This->stateBlock->lowest_disabled_stage = Stage;
4774 TRACE("New lowest disabled: %d\n", Stage);
4775 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4776 /* Previously disabled stage enabled. Stages above it may need enabling
4777 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4778 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4780 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4783 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4784 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4785 break;
4787 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4790 This->stateBlock->lowest_disabled_stage = i;
4791 TRACE("New lowest disabled: %d\n", i);
4795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4797 return WINED3D_OK;
4800 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4803 *pValue = This->updateStateBlock->textureState[Stage][Type];
4804 return WINED3D_OK;
4807 /*****
4808 * Get / Set Texture
4809 *****/
4810 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 IWineD3DBaseTexture *oldTexture;
4814 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4816 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4817 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4820 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4821 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4822 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4825 oldTexture = This->updateStateBlock->textures[Stage];
4827 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4828 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4830 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4831 return WINED3DERR_INVALIDCALL;
4834 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4835 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4837 This->updateStateBlock->changed.textures |= 1 << Stage;
4838 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4839 This->updateStateBlock->textures[Stage] = pTexture;
4841 /* Handle recording of state blocks */
4842 if (This->isRecordingState) {
4843 TRACE("Recording... not performing anything\n");
4844 return WINED3D_OK;
4847 if(oldTexture == pTexture) {
4848 TRACE("App is setting the same texture again, nothing to do\n");
4849 return WINED3D_OK;
4852 /** NOTE: MSDN says that setTexture increases the reference count,
4853 * and that the application must set the texture back to null (or have a leaky application),
4854 * This means we should pass the refcount up to the parent
4855 *******************************/
4856 if (NULL != This->updateStateBlock->textures[Stage]) {
4857 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4858 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4859 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4861 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4863 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4868 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4869 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4870 * so the COLOROP and ALPHAOP have to be dirtified.
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4875 if(bindCount == 1) {
4876 new->baseTexture.sampler = Stage;
4878 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4882 if (NULL != oldTexture) {
4883 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4884 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4886 IWineD3DBaseTexture_Release(oldTexture);
4887 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4892 if(bindCount && old->baseTexture.sampler == Stage) {
4893 int i;
4894 /* Have to do a search for the other sampler(s) where the texture is bound to
4895 * Shouldn't happen as long as apps bind a texture only to one stage
4897 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4898 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4899 if(This->updateStateBlock->textures[i] == oldTexture) {
4900 old->baseTexture.sampler = i;
4901 break;
4907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4909 return WINED3D_OK;
4912 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4917 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4918 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4921 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4922 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4923 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4926 *ppTexture=This->stateBlock->textures[Stage];
4927 if (*ppTexture)
4928 IWineD3DBaseTexture_AddRef(*ppTexture);
4930 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4932 return WINED3D_OK;
4935 /*****
4936 * Get Back Buffer
4937 *****/
4938 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4939 IWineD3DSurface **ppBackBuffer) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 IWineD3DSwapChain *swapChain;
4942 HRESULT hr;
4944 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4946 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4947 if (hr == WINED3D_OK) {
4948 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4949 IWineD3DSwapChain_Release(swapChain);
4950 } else {
4951 *ppBackBuffer = NULL;
4953 return hr;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 WARN("(%p) : stub, calling idirect3d for now\n", This);
4959 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4962 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4964 IWineD3DSwapChain *swapChain;
4965 HRESULT hr;
4967 if(iSwapChain > 0) {
4968 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4969 if (hr == WINED3D_OK) {
4970 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4971 IWineD3DSwapChain_Release(swapChain);
4972 } else {
4973 FIXME("(%p) Error getting display mode\n", This);
4975 } else {
4976 /* Don't read the real display mode,
4977 but return the stored mode instead. X11 can't change the color
4978 depth, and some apps are pretty angry if they SetDisplayMode from
4979 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4981 Also don't relay to the swapchain because with ddraw it's possible
4982 that there isn't a swapchain at all */
4983 pMode->Width = This->ddraw_width;
4984 pMode->Height = This->ddraw_height;
4985 pMode->Format = This->ddraw_format;
4986 pMode->RefreshRate = 0;
4987 hr = WINED3D_OK;
4990 return hr;
4993 /*****
4994 * Stateblock related functions
4995 *****/
4997 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 IWineD3DStateBlock *stateblock;
5000 HRESULT hr;
5002 TRACE("(%p)\n", This);
5004 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5006 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5007 if (FAILED(hr)) return hr;
5009 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5010 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5011 This->isRecordingState = TRUE;
5013 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5015 return WINED3D_OK;
5018 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 unsigned int i, j;
5021 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5023 if (!This->isRecordingState) {
5024 WARN("(%p) not recording! returning error\n", This);
5025 *ppStateBlock = NULL;
5026 return WINED3DERR_INVALIDCALL;
5029 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5031 DWORD map = object->changed.renderState[i];
5032 for (j = 0; map; map >>= 1, ++j)
5034 if (!(map & 1)) continue;
5036 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5040 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5042 DWORD map = object->changed.transform[i];
5043 for (j = 0; map; map >>= 1, ++j)
5045 if (!(map & 1)) continue;
5047 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5050 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5051 if(object->changed.vertexShaderConstantsF[i]) {
5052 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5053 object->num_contained_vs_consts_f++;
5056 for(i = 0; i < MAX_CONST_I; i++) {
5057 if (object->changed.vertexShaderConstantsI & (1 << i))
5059 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5060 object->num_contained_vs_consts_i++;
5063 for(i = 0; i < MAX_CONST_B; i++) {
5064 if (object->changed.vertexShaderConstantsB & (1 << i))
5066 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5067 object->num_contained_vs_consts_b++;
5070 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5072 if (object->changed.pixelShaderConstantsF[i])
5074 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5075 ++object->num_contained_ps_consts_f;
5078 for(i = 0; i < MAX_CONST_I; i++) {
5079 if (object->changed.pixelShaderConstantsI & (1 << i))
5081 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5082 object->num_contained_ps_consts_i++;
5085 for(i = 0; i < MAX_CONST_B; i++) {
5086 if (object->changed.pixelShaderConstantsB & (1 << i))
5088 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5089 object->num_contained_ps_consts_b++;
5092 for(i = 0; i < MAX_TEXTURES; i++) {
5093 DWORD map = object->changed.textureState[i];
5095 for(j = 0; map; map >>= 1, ++j)
5097 if (!(map & 1)) continue;
5099 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5100 object->contained_tss_states[object->num_contained_tss_states].state = j;
5101 ++object->num_contained_tss_states;
5104 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5105 DWORD map = object->changed.samplerState[i];
5107 for (j = 0; map; map >>= 1, ++j)
5109 if (!(map & 1)) continue;
5111 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5112 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5113 ++object->num_contained_sampler_states;
5117 *ppStateBlock = (IWineD3DStateBlock*) object;
5118 This->isRecordingState = FALSE;
5119 This->updateStateBlock = This->stateBlock;
5120 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5121 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5122 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5123 return WINED3D_OK;
5126 /*****
5127 * Scene related functions
5128 *****/
5129 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5130 /* At the moment we have no need for any functionality at the beginning
5131 of a scene */
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 TRACE("(%p)\n", This);
5135 if(This->inScene) {
5136 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5137 return WINED3DERR_INVALIDCALL;
5139 This->inScene = TRUE;
5140 return WINED3D_OK;
5143 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 TRACE("(%p)\n", This);
5147 if(!This->inScene) {
5148 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5149 return WINED3DERR_INVALIDCALL;
5152 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5153 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5154 glFlush();
5155 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5156 * fails
5159 This->inScene = FALSE;
5160 return WINED3D_OK;
5163 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5164 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5165 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 IWineD3DSwapChain *swapChain = NULL;
5168 int i;
5169 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5171 TRACE("(%p) Presenting the frame\n", This);
5173 for(i = 0 ; i < swapchains ; i ++) {
5175 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5176 TRACE("presentinng chain %d, %p\n", i, swapChain);
5177 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5178 IWineD3DSwapChain_Release(swapChain);
5181 return WINED3D_OK;
5184 /* Not called from the VTable (internal subroutine) */
5185 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5186 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5187 float Z, DWORD Stencil) {
5188 GLbitfield glMask = 0;
5189 unsigned int i;
5190 WINED3DRECT curRect;
5191 RECT vp_rect;
5192 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5193 UINT drawable_width, drawable_height;
5194 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5195 IWineD3DSwapChainImpl *swapchain = NULL;
5197 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5198 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5199 * for the cleared parts, and the untouched parts.
5201 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5202 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5203 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5204 * checking all this if the dest surface is in the drawable anyway.
5206 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5207 while(1) {
5208 if(vp->X != 0 || vp->Y != 0 ||
5209 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5210 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5211 break;
5213 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5214 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5215 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5216 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5217 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5218 break;
5220 if(Count > 0 && pRects && (
5221 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5222 pRects[0].x2 < target->currentDesc.Width ||
5223 pRects[0].y2 < target->currentDesc.Height)) {
5224 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5225 break;
5227 break;
5231 target->get_drawable_size(target, &drawable_width, &drawable_height);
5233 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5234 ENTER_GL();
5236 /* Only set the values up once, as they are not changing */
5237 if (Flags & WINED3DCLEAR_STENCIL) {
5238 glClearStencil(Stencil);
5239 checkGLcall("glClearStencil");
5240 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5241 glStencilMask(0xFFFFFFFF);
5244 if (Flags & WINED3DCLEAR_ZBUFFER) {
5245 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5246 glDepthMask(GL_TRUE);
5247 glClearDepth(Z);
5248 checkGLcall("glClearDepth");
5249 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5252 if (vp->X != 0 || vp->Y != 0 ||
5253 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5254 surface_load_ds_location(This->stencilBufferTarget, location);
5256 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5257 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5258 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5259 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5260 surface_load_ds_location(This->stencilBufferTarget, location);
5262 else if (Count > 0 && pRects && (
5263 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5264 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5265 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5266 surface_load_ds_location(This->stencilBufferTarget, location);
5270 if (Flags & WINED3DCLEAR_TARGET) {
5271 TRACE("Clearing screen with glClear to color %x\n", Color);
5272 glClearColor(D3DCOLOR_R(Color),
5273 D3DCOLOR_G(Color),
5274 D3DCOLOR_B(Color),
5275 D3DCOLOR_A(Color));
5276 checkGLcall("glClearColor");
5278 /* Clear ALL colors! */
5279 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5280 glMask = glMask | GL_COLOR_BUFFER_BIT;
5283 vp_rect.left = vp->X;
5284 vp_rect.top = vp->Y;
5285 vp_rect.right = vp->X + vp->Width;
5286 vp_rect.bottom = vp->Y + vp->Height;
5287 if (!(Count > 0 && pRects)) {
5288 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5289 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5291 if(This->render_offscreen) {
5292 glScissor(vp_rect.left, vp_rect.top,
5293 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5294 } else {
5295 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5296 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5298 checkGLcall("glScissor");
5299 glClear(glMask);
5300 checkGLcall("glClear");
5301 } else {
5302 /* Now process each rect in turn */
5303 for (i = 0; i < Count; i++) {
5304 /* Note gl uses lower left, width/height */
5305 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5306 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5307 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5309 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5310 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5311 curRect.x1, (target->currentDesc.Height - curRect.y2),
5312 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5314 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5315 * The rectangle is not cleared, no error is returned, but further rectanlges are
5316 * still cleared if they are valid
5318 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5319 TRACE("Rectangle with negative dimensions, ignoring\n");
5320 continue;
5323 if(This->render_offscreen) {
5324 glScissor(curRect.x1, curRect.y1,
5325 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5326 } else {
5327 glScissor(curRect.x1, drawable_height - curRect.y2,
5328 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5330 checkGLcall("glScissor");
5332 glClear(glMask);
5333 checkGLcall("glClear");
5337 /* Restore the old values (why..?) */
5338 if (Flags & WINED3DCLEAR_STENCIL) {
5339 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5341 if (Flags & WINED3DCLEAR_TARGET) {
5342 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5343 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5344 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5345 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5346 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5348 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5349 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5351 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5353 if (Flags & WINED3DCLEAR_ZBUFFER) {
5354 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5355 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5356 surface_modify_ds_location(This->stencilBufferTarget, location);
5359 LEAVE_GL();
5361 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5362 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5363 glFlush();
5365 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5368 return WINED3D_OK;
5371 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5372 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5376 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5377 Count, pRects, Flags, Color, Z, Stencil);
5379 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5380 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5381 /* TODO: What about depth stencil buffers without stencil bits? */
5382 return WINED3DERR_INVALIDCALL;
5385 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5388 /*****
5389 * Drawing functions
5390 *****/
5392 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5393 WINED3DPRIMITIVETYPE primitive_type)
5395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5397 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5399 This->updateStateBlock->changed.primitive_type = TRUE;
5400 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5403 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5404 WINED3DPRIMITIVETYPE *primitive_type)
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5408 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5410 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5412 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5415 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5419 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5421 if(!This->stateBlock->vertexDecl) {
5422 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5423 return WINED3DERR_INVALIDCALL;
5426 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5427 if(This->stateBlock->streamIsUP) {
5428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5429 This->stateBlock->streamIsUP = FALSE;
5432 if(This->stateBlock->loadBaseVertexIndex != 0) {
5433 This->stateBlock->loadBaseVertexIndex = 0;
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5436 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5437 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5438 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5439 return WINED3D_OK;
5442 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5443 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5446 UINT idxStride = 2;
5447 IWineD3DIndexBuffer *pIB;
5448 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5449 GLuint vbo;
5451 pIB = This->stateBlock->pIndexData;
5452 if (!pIB) {
5453 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5454 * without an index buffer set. (The first time at least...)
5455 * D3D8 simply dies, but I doubt it can do much harm to return
5456 * D3DERR_INVALIDCALL there as well. */
5457 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5458 return WINED3DERR_INVALIDCALL;
5461 if(!This->stateBlock->vertexDecl) {
5462 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5463 return WINED3DERR_INVALIDCALL;
5466 if(This->stateBlock->streamIsUP) {
5467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5468 This->stateBlock->streamIsUP = FALSE;
5470 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5472 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5473 This, minIndex, NumVertices, startIndex, index_count);
5475 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5476 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5477 idxStride = 2;
5478 } else {
5479 idxStride = 4;
5482 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5483 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5487 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5488 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5490 return WINED3D_OK;
5493 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5494 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5497 IWineD3DBuffer *vb;
5499 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5500 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5502 if(!This->stateBlock->vertexDecl) {
5503 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5504 return WINED3DERR_INVALIDCALL;
5507 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5508 vb = This->stateBlock->streamSource[0];
5509 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5510 if (vb) IWineD3DBuffer_Release(vb);
5511 This->stateBlock->streamOffset[0] = 0;
5512 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5513 This->stateBlock->streamIsUP = TRUE;
5514 This->stateBlock->loadBaseVertexIndex = 0;
5516 /* TODO: Only mark dirty if drawing from a different UP address */
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5519 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5520 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5522 /* MSDN specifies stream zero settings must be set to NULL */
5523 This->stateBlock->streamStride[0] = 0;
5524 This->stateBlock->streamSource[0] = NULL;
5526 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5527 * the new stream sources or use UP drawing again
5529 return WINED3D_OK;
5532 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5533 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5534 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5536 int idxStride;
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 IWineD3DBuffer *vb;
5539 IWineD3DIndexBuffer *ib;
5541 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5542 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5543 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5545 if(!This->stateBlock->vertexDecl) {
5546 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5547 return WINED3DERR_INVALIDCALL;
5550 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5551 idxStride = 2;
5552 } else {
5553 idxStride = 4;
5556 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5557 vb = This->stateBlock->streamSource[0];
5558 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5559 if (vb) IWineD3DBuffer_Release(vb);
5560 This->stateBlock->streamIsUP = TRUE;
5561 This->stateBlock->streamOffset[0] = 0;
5562 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5564 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5565 This->stateBlock->baseVertexIndex = 0;
5566 This->stateBlock->loadBaseVertexIndex = 0;
5567 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5571 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5572 idxStride, pIndexData, MinVertexIndex);
5574 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5575 This->stateBlock->streamSource[0] = NULL;
5576 This->stateBlock->streamStride[0] = 0;
5577 ib = This->stateBlock->pIndexData;
5578 if(ib) {
5579 IWineD3DIndexBuffer_Release(ib);
5580 This->stateBlock->pIndexData = NULL;
5582 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5583 * SetStreamSource to specify a vertex buffer
5586 return WINED3D_OK;
5589 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5590 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5594 /* Mark the state dirty until we have nicer tracking
5595 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5596 * that value.
5598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5600 This->stateBlock->baseVertexIndex = 0;
5601 This->up_strided = DrawPrimStrideData;
5602 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5603 This->up_strided = NULL;
5604 return WINED3D_OK;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5608 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5609 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5612 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5614 /* Mark the state dirty until we have nicer tracking
5615 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5616 * that value.
5618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5620 This->stateBlock->streamIsUP = TRUE;
5621 This->stateBlock->baseVertexIndex = 0;
5622 This->up_strided = DrawPrimStrideData;
5623 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5624 This->up_strided = NULL;
5625 return WINED3D_OK;
5628 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5629 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5630 * not callable by the app directly no parameter validation checks are needed here.
5632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5633 WINED3DLOCKED_BOX src;
5634 WINED3DLOCKED_BOX dst;
5635 HRESULT hr;
5636 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5638 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5639 * dirtification to improve loading performance.
5641 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5642 if(FAILED(hr)) return hr;
5643 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5644 if(FAILED(hr)) {
5645 IWineD3DVolume_UnlockBox(pSourceVolume);
5646 return hr;
5649 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5651 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5652 if(FAILED(hr)) {
5653 IWineD3DVolume_UnlockBox(pSourceVolume);
5654 } else {
5655 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5657 return hr;
5660 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5661 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5663 HRESULT hr = WINED3D_OK;
5664 WINED3DRESOURCETYPE sourceType;
5665 WINED3DRESOURCETYPE destinationType;
5666 int i ,levels;
5668 /* TODO: think about moving the code into IWineD3DBaseTexture */
5670 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5672 /* verify that the source and destination textures aren't NULL */
5673 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5674 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5675 This, pSourceTexture, pDestinationTexture);
5676 hr = WINED3DERR_INVALIDCALL;
5679 if (pSourceTexture == pDestinationTexture) {
5680 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5681 This, pSourceTexture, pDestinationTexture);
5682 hr = WINED3DERR_INVALIDCALL;
5684 /* Verify that the source and destination textures are the same type */
5685 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5686 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5688 if (sourceType != destinationType) {
5689 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5690 This);
5691 hr = WINED3DERR_INVALIDCALL;
5694 /* check that both textures have the identical numbers of levels */
5695 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5696 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5697 hr = WINED3DERR_INVALIDCALL;
5700 if (WINED3D_OK == hr) {
5701 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5703 /* Make sure that the destination texture is loaded */
5704 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5706 /* Update every surface level of the texture */
5707 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5709 switch (sourceType) {
5710 case WINED3DRTYPE_TEXTURE:
5712 IWineD3DSurface *srcSurface;
5713 IWineD3DSurface *destSurface;
5715 for (i = 0 ; i < levels ; ++i) {
5716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5717 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5718 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5719 IWineD3DSurface_Release(srcSurface);
5720 IWineD3DSurface_Release(destSurface);
5721 if (WINED3D_OK != hr) {
5722 WARN("(%p) : Call to update surface failed\n", This);
5723 return hr;
5727 break;
5728 case WINED3DRTYPE_CUBETEXTURE:
5730 IWineD3DSurface *srcSurface;
5731 IWineD3DSurface *destSurface;
5732 WINED3DCUBEMAP_FACES faceType;
5734 for (i = 0 ; i < levels ; ++i) {
5735 /* Update each cube face */
5736 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5737 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5738 if (WINED3D_OK != hr) {
5739 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5740 } else {
5741 TRACE("Got srcSurface %p\n", srcSurface);
5743 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5744 if (WINED3D_OK != hr) {
5745 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5746 } else {
5747 TRACE("Got desrSurface %p\n", destSurface);
5749 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5750 IWineD3DSurface_Release(srcSurface);
5751 IWineD3DSurface_Release(destSurface);
5752 if (WINED3D_OK != hr) {
5753 WARN("(%p) : Call to update surface failed\n", This);
5754 return hr;
5759 break;
5761 case WINED3DRTYPE_VOLUMETEXTURE:
5763 IWineD3DVolume *srcVolume = NULL;
5764 IWineD3DVolume *destVolume = NULL;
5766 for (i = 0 ; i < levels ; ++i) {
5767 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5768 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5769 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5770 IWineD3DVolume_Release(srcVolume);
5771 IWineD3DVolume_Release(destVolume);
5772 if (WINED3D_OK != hr) {
5773 WARN("(%p) : Call to update volume failed\n", This);
5774 return hr;
5778 break;
5780 default:
5781 FIXME("(%p) : Unsupported source and destination type\n", This);
5782 hr = WINED3DERR_INVALIDCALL;
5786 return hr;
5789 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5790 IWineD3DSwapChain *swapChain;
5791 HRESULT hr;
5792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5793 if(hr == WINED3D_OK) {
5794 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5795 IWineD3DSwapChain_Release(swapChain);
5797 return hr;
5800 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 IWineD3DBaseTextureImpl *texture;
5803 DWORD i;
5805 TRACE("(%p) : %p\n", This, pNumPasses);
5807 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5808 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5809 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5810 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5812 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5813 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5814 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5817 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5818 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5820 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5821 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5822 return E_FAIL;
5824 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5825 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5826 return E_FAIL;
5828 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5829 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5830 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5831 return E_FAIL;
5835 /* return a sensible default */
5836 *pNumPasses = 1;
5838 TRACE("returning D3D_OK\n");
5839 return WINED3D_OK;
5842 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5844 int i;
5846 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5847 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5848 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5849 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5851 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5856 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 int j;
5859 UINT NewSize;
5860 PALETTEENTRY **palettes;
5862 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5864 if (PaletteNumber >= MAX_PALETTES) {
5865 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5866 return WINED3DERR_INVALIDCALL;
5869 if (PaletteNumber >= This->NumberOfPalettes) {
5870 NewSize = This->NumberOfPalettes;
5871 do {
5872 NewSize *= 2;
5873 } while(PaletteNumber >= NewSize);
5874 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5875 if (!palettes) {
5876 ERR("Out of memory!\n");
5877 return E_OUTOFMEMORY;
5879 This->palettes = palettes;
5880 This->NumberOfPalettes = NewSize;
5883 if (!This->palettes[PaletteNumber]) {
5884 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5885 if (!This->palettes[PaletteNumber]) {
5886 ERR("Out of memory!\n");
5887 return E_OUTOFMEMORY;
5891 for (j = 0; j < 256; ++j) {
5892 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5893 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5894 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5895 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5897 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5898 TRACE("(%p) : returning\n", This);
5899 return WINED3D_OK;
5902 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5904 int j;
5905 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5906 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5907 /* What happens in such situation isn't documented; Native seems to silently abort
5908 on such conditions. Return Invalid Call. */
5909 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5910 return WINED3DERR_INVALIDCALL;
5912 for (j = 0; j < 256; ++j) {
5913 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5914 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5915 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5916 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5918 TRACE("(%p) : returning\n", This);
5919 return WINED3D_OK;
5922 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5924 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5925 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5926 (tested with reference rasterizer). Return Invalid Call. */
5927 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5928 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5929 return WINED3DERR_INVALIDCALL;
5931 /*TODO: stateblocks */
5932 if (This->currentPalette != PaletteNumber) {
5933 This->currentPalette = PaletteNumber;
5934 dirtify_p8_texture_samplers(This);
5936 TRACE("(%p) : returning\n", This);
5937 return WINED3D_OK;
5940 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5942 if (PaletteNumber == NULL) {
5943 WARN("(%p) : returning Invalid Call\n", This);
5944 return WINED3DERR_INVALIDCALL;
5946 /*TODO: stateblocks */
5947 *PaletteNumber = This->currentPalette;
5948 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5949 return WINED3D_OK;
5952 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5954 static BOOL warned;
5955 if (!warned)
5957 FIXME("(%p) : stub\n", This);
5958 warned = TRUE;
5961 This->softwareVertexProcessing = bSoftware;
5962 return WINED3D_OK;
5966 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5968 static BOOL warned;
5969 if (!warned)
5971 FIXME("(%p) : stub\n", This);
5972 warned = TRUE;
5974 return This->softwareVertexProcessing;
5978 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5980 IWineD3DSwapChain *swapChain;
5981 HRESULT hr;
5983 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5985 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5986 if(hr == WINED3D_OK){
5987 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5988 IWineD3DSwapChain_Release(swapChain);
5989 }else{
5990 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5992 return hr;
5996 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5998 static BOOL warned;
5999 if(nSegments != 0.0f) {
6000 if (!warned)
6002 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6003 warned = TRUE;
6006 return WINED3D_OK;
6009 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6011 static BOOL warned;
6012 if (!warned)
6014 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6015 warned = TRUE;
6017 return 0.0f;
6020 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6022 /** TODO: remove casts to IWineD3DSurfaceImpl
6023 * NOTE: move code to surface to accomplish this
6024 ****************************************/
6025 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6026 int srcWidth, srcHeight;
6027 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6028 WINED3DFORMAT destFormat, srcFormat;
6029 UINT destSize;
6030 int srcLeft, destLeft, destTop;
6031 WINED3DPOOL srcPool, destPool;
6032 int offset = 0;
6033 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6034 glDescriptor *glDescription = NULL;
6035 const struct GlPixelFormatDesc *dst_format_desc;
6036 GLenum dummy;
6037 int sampler;
6038 int bpp;
6039 CONVERT_TYPES convert = NO_CONVERSION;
6041 WINED3DSURFACE_DESC winedesc;
6043 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6044 memset(&winedesc, 0, sizeof(winedesc));
6045 winedesc.Width = &srcSurfaceWidth;
6046 winedesc.Height = &srcSurfaceHeight;
6047 winedesc.Pool = &srcPool;
6048 winedesc.Format = &srcFormat;
6050 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6052 winedesc.Width = &destSurfaceWidth;
6053 winedesc.Height = &destSurfaceHeight;
6054 winedesc.Pool = &destPool;
6055 winedesc.Format = &destFormat;
6056 winedesc.Size = &destSize;
6058 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6060 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6061 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6062 return WINED3DERR_INVALIDCALL;
6065 /* This call loads the opengl surface directly, instead of copying the surface to the
6066 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6067 * copy in sysmem and use regular surface loading.
6069 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6070 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6071 if(convert != NO_CONVERSION) {
6072 return IWineD3DSurface_BltFast(pDestinationSurface,
6073 pDestPoint ? pDestPoint->x : 0,
6074 pDestPoint ? pDestPoint->y : 0,
6075 pSourceSurface, pSourceRect, 0);
6078 if (destFormat == WINED3DFMT_UNKNOWN) {
6079 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6080 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6082 /* Get the update surface description */
6083 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6086 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6088 ENTER_GL();
6089 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6090 checkGLcall("glActiveTextureARB");
6091 LEAVE_GL();
6093 /* Make sure the surface is loaded and up to date */
6094 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6095 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6097 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6099 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6101 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6102 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6103 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6104 srcLeft = pSourceRect ? pSourceRect->left : 0;
6105 destLeft = pDestPoint ? pDestPoint->x : 0;
6106 destTop = pDestPoint ? pDestPoint->y : 0;
6109 /* This function doesn't support compressed textures
6110 the pitch is just bytesPerPixel * width */
6111 if(srcWidth != srcSurfaceWidth || srcLeft ){
6112 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6113 offset += srcLeft * pSrcSurface->bytesPerPixel;
6114 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6116 /* TODO DXT formats */
6118 if(pSourceRect != NULL && pSourceRect->top != 0){
6119 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6121 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6122 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6123 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6125 /* Sanity check */
6126 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6128 /* need to lock the surface to get the data */
6129 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6132 ENTER_GL();
6134 /* TODO: Cube and volume support */
6135 if(rowoffset != 0){
6136 /* not a whole row so we have to do it a line at a time */
6137 int j;
6139 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6140 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6142 for (j = destTop; j < (srcHeight + destTop); ++j)
6144 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6145 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6146 data += rowoffset;
6149 } else { /* Full width, so just write out the whole texture */
6150 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6152 if (WINED3DFMT_DXT1 == destFormat ||
6153 WINED3DFMT_DXT2 == destFormat ||
6154 WINED3DFMT_DXT3 == destFormat ||
6155 WINED3DFMT_DXT4 == destFormat ||
6156 WINED3DFMT_DXT5 == destFormat) {
6157 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6158 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6159 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6160 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6161 } if (destFormat != srcFormat) {
6162 FIXME("Updating mixed format compressed texture is not curretly support\n");
6163 } else {
6164 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6165 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6167 } else {
6168 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6172 } else {
6173 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6174 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6177 checkGLcall("glTexSubImage2D");
6179 LEAVE_GL();
6181 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6182 sampler = This->rev_tex_unit_map[0];
6183 if (sampler != -1) {
6184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6187 return WINED3D_OK;
6190 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6192 struct WineD3DRectPatch *patch;
6193 GLenum old_primitive_type;
6194 unsigned int i;
6195 struct list *e;
6196 BOOL found;
6197 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6199 if(!(Handle || pRectPatchInfo)) {
6200 /* TODO: Write a test for the return value, thus the FIXME */
6201 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6202 return WINED3DERR_INVALIDCALL;
6205 if(Handle) {
6206 i = PATCHMAP_HASHFUNC(Handle);
6207 found = FALSE;
6208 LIST_FOR_EACH(e, &This->patches[i]) {
6209 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6210 if(patch->Handle == Handle) {
6211 found = TRUE;
6212 break;
6216 if(!found) {
6217 TRACE("Patch does not exist. Creating a new one\n");
6218 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6219 patch->Handle = Handle;
6220 list_add_head(&This->patches[i], &patch->entry);
6221 } else {
6222 TRACE("Found existing patch %p\n", patch);
6224 } else {
6225 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6226 * attributes we have to tesselate, read back, and draw. This needs a patch
6227 * management structure instance. Create one.
6229 * A possible improvement is to check if a vertex shader is used, and if not directly
6230 * draw the patch.
6232 FIXME("Drawing an uncached patch. This is slow\n");
6233 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6236 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6237 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6238 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6239 HRESULT hr;
6240 TRACE("Tesselation density or patch info changed, retesselating\n");
6242 if(pRectPatchInfo) {
6243 patch->RectPatchInfo = *pRectPatchInfo;
6245 patch->numSegs[0] = pNumSegs[0];
6246 patch->numSegs[1] = pNumSegs[1];
6247 patch->numSegs[2] = pNumSegs[2];
6248 patch->numSegs[3] = pNumSegs[3];
6250 hr = tesselate_rectpatch(This, patch);
6251 if(FAILED(hr)) {
6252 WARN("Patch tesselation failed\n");
6254 /* Do not release the handle to store the params of the patch */
6255 if(!Handle) {
6256 HeapFree(GetProcessHeap(), 0, patch);
6258 return hr;
6262 This->currentPatch = patch;
6263 old_primitive_type = This->stateBlock->gl_primitive_type;
6264 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6265 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6266 This->stateBlock->gl_primitive_type = old_primitive_type;
6267 This->currentPatch = NULL;
6269 /* Destroy uncached patches */
6270 if(!Handle) {
6271 HeapFree(GetProcessHeap(), 0, patch->mem);
6272 HeapFree(GetProcessHeap(), 0, patch);
6274 return WINED3D_OK;
6277 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6279 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6280 FIXME("(%p) : Stub\n", This);
6281 return WINED3D_OK;
6284 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6286 int i;
6287 struct WineD3DRectPatch *patch;
6288 struct list *e;
6289 TRACE("(%p) Handle(%d)\n", This, Handle);
6291 i = PATCHMAP_HASHFUNC(Handle);
6292 LIST_FOR_EACH(e, &This->patches[i]) {
6293 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6294 if(patch->Handle == Handle) {
6295 TRACE("Deleting patch %p\n", patch);
6296 list_remove(&patch->entry);
6297 HeapFree(GetProcessHeap(), 0, patch->mem);
6298 HeapFree(GetProcessHeap(), 0, patch);
6299 return WINED3D_OK;
6303 /* TODO: Write a test for the return value */
6304 FIXME("Attempt to destroy nonexistent patch\n");
6305 return WINED3DERR_INVALIDCALL;
6308 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6309 HRESULT hr;
6310 IWineD3DSwapChain *swapchain;
6312 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6313 if (SUCCEEDED(hr)) {
6314 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6315 return swapchain;
6318 return NULL;
6321 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6322 const WINED3DRECT *rect, const float color[4])
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6325 IWineD3DSwapChain *swapchain;
6327 swapchain = get_swapchain(surface);
6328 if (swapchain) {
6329 GLenum buffer;
6331 TRACE("Surface %p is onscreen\n", surface);
6333 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6334 ENTER_GL();
6335 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6336 buffer = surface_get_gl_buffer(surface, swapchain);
6337 glDrawBuffer(buffer);
6338 checkGLcall("glDrawBuffer()");
6339 } else {
6340 TRACE("Surface %p is offscreen\n", surface);
6342 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6343 ENTER_GL();
6344 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6345 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6346 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6347 checkGLcall("glFramebufferRenderbufferEXT");
6350 if (rect) {
6351 glEnable(GL_SCISSOR_TEST);
6352 if(!swapchain) {
6353 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6354 } else {
6355 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6356 rect->x2 - rect->x1, rect->y2 - rect->y1);
6358 checkGLcall("glScissor");
6359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6360 } else {
6361 glDisable(GL_SCISSOR_TEST);
6363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6365 glDisable(GL_BLEND);
6366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6368 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6371 glClearColor(color[0], color[1], color[2], color[3]);
6372 glClear(GL_COLOR_BUFFER_BIT);
6373 checkGLcall("glClear");
6375 if (This->activeContext->current_fbo) {
6376 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6377 } else {
6378 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6379 checkGLcall("glBindFramebuffer()");
6382 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6383 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6384 glDrawBuffer(GL_BACK);
6385 checkGLcall("glDrawBuffer()");
6388 LEAVE_GL();
6391 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6392 unsigned int r, g, b, a;
6393 DWORD ret;
6395 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6396 destfmt == WINED3DFMT_R8G8B8)
6397 return color;
6399 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6401 a = (color & 0xff000000) >> 24;
6402 r = (color & 0x00ff0000) >> 16;
6403 g = (color & 0x0000ff00) >> 8;
6404 b = (color & 0x000000ff) >> 0;
6406 switch(destfmt)
6408 case WINED3DFMT_R5G6B5:
6409 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6410 r = (r * 32) / 256;
6411 g = (g * 64) / 256;
6412 b = (b * 32) / 256;
6413 ret = r << 11;
6414 ret |= g << 5;
6415 ret |= b;
6416 TRACE("Returning %08x\n", ret);
6417 return ret;
6419 case WINED3DFMT_X1R5G5B5:
6420 case WINED3DFMT_A1R5G5B5:
6421 a = (a * 2) / 256;
6422 r = (r * 32) / 256;
6423 g = (g * 32) / 256;
6424 b = (b * 32) / 256;
6425 ret = a << 15;
6426 ret |= r << 10;
6427 ret |= g << 5;
6428 ret |= b << 0;
6429 TRACE("Returning %08x\n", ret);
6430 return ret;
6432 case WINED3DFMT_A8_UNORM:
6433 TRACE("Returning %08x\n", a);
6434 return a;
6436 case WINED3DFMT_X4R4G4B4:
6437 case WINED3DFMT_A4R4G4B4:
6438 a = (a * 16) / 256;
6439 r = (r * 16) / 256;
6440 g = (g * 16) / 256;
6441 b = (b * 16) / 256;
6442 ret = a << 12;
6443 ret |= r << 8;
6444 ret |= g << 4;
6445 ret |= b << 0;
6446 TRACE("Returning %08x\n", ret);
6447 return ret;
6449 case WINED3DFMT_R3G3B2:
6450 r = (r * 8) / 256;
6451 g = (g * 8) / 256;
6452 b = (b * 4) / 256;
6453 ret = r << 5;
6454 ret |= g << 2;
6455 ret |= b << 0;
6456 TRACE("Returning %08x\n", ret);
6457 return ret;
6459 case WINED3DFMT_X8B8G8R8:
6460 case WINED3DFMT_R8G8B8A8_UNORM:
6461 ret = a << 24;
6462 ret |= b << 16;
6463 ret |= g << 8;
6464 ret |= r << 0;
6465 TRACE("Returning %08x\n", ret);
6466 return ret;
6468 case WINED3DFMT_A2R10G10B10:
6469 a = (a * 4) / 256;
6470 r = (r * 1024) / 256;
6471 g = (g * 1024) / 256;
6472 b = (b * 1024) / 256;
6473 ret = a << 30;
6474 ret |= r << 20;
6475 ret |= g << 10;
6476 ret |= b << 0;
6477 TRACE("Returning %08x\n", ret);
6478 return ret;
6480 case WINED3DFMT_R10G10B10A2_UNORM:
6481 a = (a * 4) / 256;
6482 r = (r * 1024) / 256;
6483 g = (g * 1024) / 256;
6484 b = (b * 1024) / 256;
6485 ret = a << 30;
6486 ret |= b << 20;
6487 ret |= g << 10;
6488 ret |= r << 0;
6489 TRACE("Returning %08x\n", ret);
6490 return ret;
6492 default:
6493 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6494 return 0;
6498 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6500 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6501 WINEDDBLTFX BltFx;
6502 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6504 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6505 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6506 return WINED3DERR_INVALIDCALL;
6509 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6510 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6511 color_fill_fbo(iface, pSurface, pRect, c);
6512 return WINED3D_OK;
6513 } else {
6514 /* Just forward this to the DirectDraw blitting engine */
6515 memset(&BltFx, 0, sizeof(BltFx));
6516 BltFx.dwSize = sizeof(BltFx);
6517 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6518 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6519 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6523 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6524 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6526 IWineD3DResource *resource;
6527 IWineD3DSurface *surface;
6528 HRESULT hr;
6530 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6531 if (FAILED(hr))
6533 ERR("Failed to get resource, hr %#x\n", hr);
6534 return;
6537 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6539 FIXME("Only supported on surface resources\n");
6540 IWineD3DResource_Release(resource);
6541 return;
6544 surface = (IWineD3DSurface *)resource;
6546 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6548 color_fill_fbo(iface, surface, NULL, color);
6550 else
6552 WINEDDBLTFX BltFx;
6553 WINED3DCOLOR c;
6555 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6557 c = ((DWORD)(color[2] * 255.0));
6558 c |= ((DWORD)(color[1] * 255.0)) << 8;
6559 c |= ((DWORD)(color[0] * 255.0)) << 16;
6560 c |= ((DWORD)(color[3] * 255.0)) << 24;
6562 /* Just forward this to the DirectDraw blitting engine */
6563 memset(&BltFx, 0, sizeof(BltFx));
6564 BltFx.dwSize = sizeof(BltFx);
6565 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6566 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6567 if (FAILED(hr))
6569 ERR("Blt failed, hr %#x\n", hr);
6573 IWineD3DResource_Release(resource);
6576 /* rendertarget and depth stencil functions */
6577 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6580 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6581 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6582 return WINED3DERR_INVALIDCALL;
6585 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6586 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6587 /* Note inc ref on returned surface */
6588 if(*ppRenderTarget != NULL)
6589 IWineD3DSurface_AddRef(*ppRenderTarget);
6590 return WINED3D_OK;
6593 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6595 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6596 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6597 IWineD3DSwapChainImpl *Swapchain;
6598 HRESULT hr;
6600 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6602 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6603 if(hr != WINED3D_OK) {
6604 ERR("Can't get the swapchain\n");
6605 return hr;
6608 /* Make sure to release the swapchain */
6609 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6611 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6612 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6613 return WINED3DERR_INVALIDCALL;
6615 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6616 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6617 return WINED3DERR_INVALIDCALL;
6620 if(Swapchain->frontBuffer != Front) {
6621 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6623 if(Swapchain->frontBuffer)
6624 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6625 Swapchain->frontBuffer = Front;
6627 if(Swapchain->frontBuffer) {
6628 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6632 if(Back && !Swapchain->backBuffer) {
6633 /* We need memory for the back buffer array - only one back buffer this way */
6634 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6635 if(!Swapchain->backBuffer) {
6636 ERR("Out of memory\n");
6637 return E_OUTOFMEMORY;
6641 if(Swapchain->backBuffer[0] != Back) {
6642 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6644 /* What to do about the context here in the case of multithreading? Not sure.
6645 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6647 ENTER_GL();
6648 if(!Swapchain->backBuffer[0]) {
6649 /* GL was told to draw to the front buffer at creation,
6650 * undo that
6652 glDrawBuffer(GL_BACK);
6653 checkGLcall("glDrawBuffer(GL_BACK)");
6654 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6655 Swapchain->presentParms.BackBufferCount = 1;
6656 } else if (!Back) {
6657 /* That makes problems - disable for now */
6658 /* glDrawBuffer(GL_FRONT); */
6659 checkGLcall("glDrawBuffer(GL_FRONT)");
6660 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6661 Swapchain->presentParms.BackBufferCount = 0;
6663 LEAVE_GL();
6665 if(Swapchain->backBuffer[0])
6666 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6667 Swapchain->backBuffer[0] = Back;
6669 if(Swapchain->backBuffer[0]) {
6670 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6671 } else {
6672 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6673 Swapchain->backBuffer = NULL;
6678 return WINED3D_OK;
6681 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6683 *ppZStencilSurface = This->stencilBufferTarget;
6684 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6686 if(*ppZStencilSurface != NULL) {
6687 /* Note inc ref on returned surface */
6688 IWineD3DSurface_AddRef(*ppZStencilSurface);
6689 return WINED3D_OK;
6690 } else {
6691 return WINED3DERR_NOTFOUND;
6695 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6696 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6699 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6700 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6701 GLenum gl_filter;
6702 POINT offset = {0, 0};
6704 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6705 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6706 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6707 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6709 switch (filter) {
6710 case WINED3DTEXF_LINEAR:
6711 gl_filter = GL_LINEAR;
6712 break;
6714 default:
6715 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6716 case WINED3DTEXF_NONE:
6717 case WINED3DTEXF_POINT:
6718 gl_filter = GL_NEAREST;
6719 break;
6722 /* Attach src surface to src fbo */
6723 src_swapchain = get_swapchain(src_surface);
6724 if (src_swapchain) {
6725 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6727 TRACE("Source surface %p is onscreen\n", src_surface);
6728 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6729 /* Make sure the drawable is up to date. In the offscreen case
6730 * attach_surface_fbo() implicitly takes care of this. */
6731 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6733 if(buffer == GL_FRONT) {
6734 RECT windowsize;
6735 UINT h;
6736 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6737 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6738 h = windowsize.bottom - windowsize.top;
6739 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6740 src_rect->y1 = offset.y + h - src_rect->y1;
6741 src_rect->y2 = offset.y + h - src_rect->y2;
6742 } else {
6743 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6744 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6747 ENTER_GL();
6748 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6749 glReadBuffer(buffer);
6750 checkGLcall("glReadBuffer()");
6751 } else {
6752 TRACE("Source surface %p is offscreen\n", src_surface);
6753 ENTER_GL();
6754 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6755 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6756 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6757 checkGLcall("glReadBuffer()");
6758 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6759 checkGLcall("glFramebufferRenderbufferEXT");
6761 LEAVE_GL();
6763 /* Attach dst surface to dst fbo */
6764 dst_swapchain = get_swapchain(dst_surface);
6765 if (dst_swapchain) {
6766 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6768 TRACE("Destination surface %p is onscreen\n", dst_surface);
6769 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6770 /* Make sure the drawable is up to date. In the offscreen case
6771 * attach_surface_fbo() implicitly takes care of this. */
6772 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6774 if(buffer == GL_FRONT) {
6775 RECT windowsize;
6776 UINT h;
6777 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6778 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6779 h = windowsize.bottom - windowsize.top;
6780 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6781 dst_rect->y1 = offset.y + h - dst_rect->y1;
6782 dst_rect->y2 = offset.y + h - dst_rect->y2;
6783 } else {
6784 /* Screen coords = window coords, surface height = window height */
6785 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6786 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6789 ENTER_GL();
6790 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6791 glDrawBuffer(buffer);
6792 checkGLcall("glDrawBuffer()");
6793 } else {
6794 TRACE("Destination surface %p is offscreen\n", dst_surface);
6796 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6797 if(!src_swapchain) {
6798 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6801 ENTER_GL();
6802 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6803 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6804 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6805 checkGLcall("glDrawBuffer()");
6806 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6807 checkGLcall("glFramebufferRenderbufferEXT");
6809 glDisable(GL_SCISSOR_TEST);
6810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6812 if (flip) {
6813 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6814 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6815 checkGLcall("glBlitFramebuffer()");
6816 } else {
6817 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6818 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6819 checkGLcall("glBlitFramebuffer()");
6822 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6824 if (This->activeContext->current_fbo) {
6825 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6826 } else {
6827 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6828 checkGLcall("glBindFramebuffer()");
6831 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6832 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6833 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6834 glDrawBuffer(GL_BACK);
6835 checkGLcall("glDrawBuffer()");
6837 LEAVE_GL();
6840 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6842 WINED3DVIEWPORT viewport;
6844 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6846 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6847 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6848 This, RenderTargetIndex, GL_LIMITS(buffers));
6849 return WINED3DERR_INVALIDCALL;
6852 /* MSDN says that null disables the render target
6853 but a device must always be associated with a render target
6854 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6856 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6857 FIXME("Trying to set render target 0 to NULL\n");
6858 return WINED3DERR_INVALIDCALL;
6860 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6861 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);
6862 return WINED3DERR_INVALIDCALL;
6865 /* If we are trying to set what we already have, don't bother */
6866 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6867 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6868 return WINED3D_OK;
6870 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6871 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6872 This->render_targets[RenderTargetIndex] = pRenderTarget;
6874 /* Render target 0 is special */
6875 if(RenderTargetIndex == 0) {
6876 /* Finally, reset the viewport as the MSDN states. */
6877 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6878 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6879 viewport.X = 0;
6880 viewport.Y = 0;
6881 viewport.MaxZ = 1.0f;
6882 viewport.MinZ = 0.0f;
6883 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6884 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6885 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6889 return WINED3D_OK;
6892 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6894 HRESULT hr = WINED3D_OK;
6895 IWineD3DSurface *tmp;
6897 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6899 if (pNewZStencil == This->stencilBufferTarget) {
6900 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6901 } else {
6902 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6903 * depending on the renter target implementation being used.
6904 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6905 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6906 * stencil buffer and incur an extra memory overhead
6907 ******************************************************/
6909 if (This->stencilBufferTarget) {
6910 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6911 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6912 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6913 } else {
6914 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6915 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6916 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6920 tmp = This->stencilBufferTarget;
6921 This->stencilBufferTarget = pNewZStencil;
6922 /* should we be calling the parent or the wined3d surface? */
6923 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6924 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6925 hr = WINED3D_OK;
6927 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6928 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6935 return hr;
6938 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6939 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6941 /* TODO: the use of Impl is deprecated. */
6942 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6943 WINED3DLOCKED_RECT lockedRect;
6945 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6947 /* some basic validation checks */
6948 if(This->cursorTexture) {
6949 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6950 ENTER_GL();
6951 glDeleteTextures(1, &This->cursorTexture);
6952 LEAVE_GL();
6953 This->cursorTexture = 0;
6956 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6957 This->haveHardwareCursor = TRUE;
6958 else
6959 This->haveHardwareCursor = FALSE;
6961 if(pCursorBitmap) {
6962 WINED3DLOCKED_RECT rect;
6964 /* MSDN: Cursor must be A8R8G8B8 */
6965 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6967 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6968 return WINED3DERR_INVALIDCALL;
6971 /* MSDN: Cursor must be smaller than the display mode */
6972 if(pSur->currentDesc.Width > This->ddraw_width ||
6973 pSur->currentDesc.Height > This->ddraw_height) {
6974 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);
6975 return WINED3DERR_INVALIDCALL;
6978 if (!This->haveHardwareCursor) {
6979 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6981 /* Do not store the surface's pointer because the application may
6982 * release it after setting the cursor image. Windows doesn't
6983 * addref the set surface, so we can't do this either without
6984 * creating circular refcount dependencies. Copy out the gl texture
6985 * instead.
6987 This->cursorWidth = pSur->currentDesc.Width;
6988 This->cursorHeight = pSur->currentDesc.Height;
6989 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6991 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6992 char *mem, *bits = rect.pBits;
6993 GLint intfmt = glDesc->glInternal;
6994 GLint format = glDesc->glFormat;
6995 GLint type = glDesc->glType;
6996 INT height = This->cursorHeight;
6997 INT width = This->cursorWidth;
6998 INT bpp = glDesc->byte_count;
6999 INT i, sampler;
7001 /* Reformat the texture memory (pitch and width can be
7002 * different) */
7003 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7004 for(i = 0; i < height; i++)
7005 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7006 IWineD3DSurface_UnlockRect(pCursorBitmap);
7007 ENTER_GL();
7009 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7010 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7011 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7014 /* Make sure that a proper texture unit is selected */
7015 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7016 checkGLcall("glActiveTextureARB");
7017 sampler = This->rev_tex_unit_map[0];
7018 if (sampler != -1) {
7019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7021 /* Create a new cursor texture */
7022 glGenTextures(1, &This->cursorTexture);
7023 checkGLcall("glGenTextures");
7024 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7025 checkGLcall("glBindTexture");
7026 /* Copy the bitmap memory into the cursor texture */
7027 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7028 HeapFree(GetProcessHeap(), 0, mem);
7029 checkGLcall("glTexImage2D");
7031 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7036 LEAVE_GL();
7038 else
7040 FIXME("A cursor texture was not returned.\n");
7041 This->cursorTexture = 0;
7044 else
7046 /* Draw a hardware cursor */
7047 ICONINFO cursorInfo;
7048 HCURSOR cursor;
7049 /* Create and clear maskBits because it is not needed for
7050 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7051 * chunks. */
7052 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7053 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7054 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7055 WINED3DLOCK_NO_DIRTY_UPDATE |
7056 WINED3DLOCK_READONLY
7058 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7059 pSur->currentDesc.Height);
7061 cursorInfo.fIcon = FALSE;
7062 cursorInfo.xHotspot = XHotSpot;
7063 cursorInfo.yHotspot = YHotSpot;
7064 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7065 pSur->currentDesc.Height, 1,
7066 1, &maskBits);
7067 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7068 pSur->currentDesc.Height, 1,
7069 32, lockedRect.pBits);
7070 IWineD3DSurface_UnlockRect(pCursorBitmap);
7071 /* Create our cursor and clean up. */
7072 cursor = CreateIconIndirect(&cursorInfo);
7073 SetCursor(cursor);
7074 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7075 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7076 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7077 This->hardwareCursor = cursor;
7078 HeapFree(GetProcessHeap(), 0, maskBits);
7082 This->xHotSpot = XHotSpot;
7083 This->yHotSpot = YHotSpot;
7084 return WINED3D_OK;
7087 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7089 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7091 This->xScreenSpace = XScreenSpace;
7092 This->yScreenSpace = YScreenSpace;
7094 return;
7098 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7100 BOOL oldVisible = This->bCursorVisible;
7101 POINT pt;
7103 TRACE("(%p) : visible(%d)\n", This, bShow);
7106 * When ShowCursor is first called it should make the cursor appear at the OS's last
7107 * known cursor position. Because of this, some applications just repetitively call
7108 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7110 GetCursorPos(&pt);
7111 This->xScreenSpace = pt.x;
7112 This->yScreenSpace = pt.y;
7114 if (This->haveHardwareCursor) {
7115 This->bCursorVisible = bShow;
7116 if (bShow)
7117 SetCursor(This->hardwareCursor);
7118 else
7119 SetCursor(NULL);
7121 else
7123 if (This->cursorTexture)
7124 This->bCursorVisible = bShow;
7127 return oldVisible;
7130 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7132 IWineD3DResourceImpl *resource;
7133 TRACE("(%p) : state (%u)\n", This, This->state);
7135 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7136 switch (This->state) {
7137 case WINED3D_OK:
7138 return WINED3D_OK;
7139 case WINED3DERR_DEVICELOST:
7141 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7142 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7143 return WINED3DERR_DEVICENOTRESET;
7145 return WINED3DERR_DEVICELOST;
7147 case WINED3DERR_DRIVERINTERNALERROR:
7148 return WINED3DERR_DRIVERINTERNALERROR;
7151 /* Unknown state */
7152 return WINED3DERR_DRIVERINTERNALERROR;
7156 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7158 /** FIXME: Resource tracking needs to be done,
7159 * The closes we can do to this is set the priorities of all managed textures low
7160 * and then reset them.
7161 ***********************************************************/
7162 FIXME("(%p) : stub\n", This);
7163 return WINED3D_OK;
7166 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7168 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7170 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7171 if(surface->Flags & SFLAG_DIBSECTION) {
7172 /* Release the DC */
7173 SelectObject(surface->hDC, surface->dib.holdbitmap);
7174 DeleteDC(surface->hDC);
7175 /* Release the DIB section */
7176 DeleteObject(surface->dib.DIBsection);
7177 surface->dib.bitmap_data = NULL;
7178 surface->resource.allocatedMemory = NULL;
7179 surface->Flags &= ~SFLAG_DIBSECTION;
7181 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7182 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7183 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7184 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7185 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7186 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7187 } else {
7188 surface->pow2Width = surface->pow2Height = 1;
7189 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7190 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7192 surface->glRect.left = 0;
7193 surface->glRect.top = 0;
7194 surface->glRect.right = surface->pow2Width;
7195 surface->glRect.bottom = surface->pow2Height;
7197 if(surface->glDescription.textureName) {
7198 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7199 ENTER_GL();
7200 glDeleteTextures(1, &surface->glDescription.textureName);
7201 LEAVE_GL();
7202 surface->glDescription.textureName = 0;
7203 surface->Flags &= ~SFLAG_CLIENT;
7205 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7206 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7207 surface->Flags |= SFLAG_NONPOW2;
7208 } else {
7209 surface->Flags &= ~SFLAG_NONPOW2;
7211 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7212 surface->resource.allocatedMemory = NULL;
7213 surface->resource.heapMemory = NULL;
7214 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7215 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7216 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7217 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7218 } else {
7219 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7223 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7224 TRACE("Unloading resource %p\n", resource);
7225 IWineD3DResource_UnLoad(resource);
7226 IWineD3DResource_Release(resource);
7227 return S_OK;
7230 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7232 UINT i, count;
7233 WINED3DDISPLAYMODE m;
7234 HRESULT hr;
7236 /* All Windowed modes are supported, as is leaving the current mode */
7237 if(pp->Windowed) return TRUE;
7238 if(!pp->BackBufferWidth) return TRUE;
7239 if(!pp->BackBufferHeight) return TRUE;
7241 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7242 for(i = 0; i < count; i++) {
7243 memset(&m, 0, sizeof(m));
7244 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7245 if(FAILED(hr)) {
7246 ERR("EnumAdapterModes failed\n");
7248 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7249 /* Mode found, it is supported */
7250 return TRUE;
7253 /* Mode not found -> not supported */
7254 return FALSE;
7257 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7259 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7260 UINT i;
7261 IWineD3DBaseShaderImpl *shader;
7263 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7264 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7265 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7268 ENTER_GL();
7269 if(This->depth_blt_texture) {
7270 glDeleteTextures(1, &This->depth_blt_texture);
7271 This->depth_blt_texture = 0;
7273 if (This->depth_blt_rb) {
7274 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7275 This->depth_blt_rb = 0;
7276 This->depth_blt_rb_w = 0;
7277 This->depth_blt_rb_h = 0;
7279 LEAVE_GL();
7281 This->blitter->free_private(iface);
7282 This->frag_pipe->free_private(iface);
7283 This->shader_backend->shader_free_private(iface);
7285 ENTER_GL();
7286 for (i = 0; i < GL_LIMITS(textures); i++) {
7287 /* Textures are recreated below */
7288 glDeleteTextures(1, &This->dummyTextureName[i]);
7289 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7290 This->dummyTextureName[i] = 0;
7292 LEAVE_GL();
7294 while(This->numContexts) {
7295 DestroyContext(This, This->contexts[0]);
7297 This->activeContext = NULL;
7298 HeapFree(GetProcessHeap(), 0, swapchain->context);
7299 swapchain->context = NULL;
7300 swapchain->num_contexts = 0;
7303 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7305 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7306 HRESULT hr;
7307 IWineD3DSurfaceImpl *target;
7309 /* Recreate the primary swapchain's context */
7310 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7311 if(swapchain->backBuffer) {
7312 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7313 } else {
7314 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7316 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7317 &swapchain->presentParms);
7318 swapchain->num_contexts = 1;
7319 This->activeContext = swapchain->context[0];
7321 create_dummy_textures(This);
7323 hr = This->shader_backend->shader_alloc_private(iface);
7324 if(FAILED(hr)) {
7325 ERR("Failed to recreate shader private data\n");
7326 goto err_out;
7328 hr = This->frag_pipe->alloc_private(iface);
7329 if(FAILED(hr)) {
7330 TRACE("Fragment pipeline private data couldn't be allocated\n");
7331 goto err_out;
7333 hr = This->blitter->alloc_private(iface);
7334 if(FAILED(hr)) {
7335 TRACE("Blitter private data couldn't be allocated\n");
7336 goto err_out;
7339 return WINED3D_OK;
7341 err_out:
7342 This->blitter->free_private(iface);
7343 This->frag_pipe->free_private(iface);
7344 This->shader_backend->shader_free_private(iface);
7345 return hr;
7348 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7350 IWineD3DSwapChainImpl *swapchain;
7351 HRESULT hr;
7352 BOOL DisplayModeChanged = FALSE;
7353 WINED3DDISPLAYMODE mode;
7354 TRACE("(%p)\n", This);
7356 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7357 if(FAILED(hr)) {
7358 ERR("Failed to get the first implicit swapchain\n");
7359 return hr;
7362 if(!is_display_mode_supported(This, pPresentationParameters)) {
7363 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7364 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7365 pPresentationParameters->BackBufferHeight);
7366 return WINED3DERR_INVALIDCALL;
7369 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7370 * on an existing gl context, so there's no real need for recreation.
7372 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7374 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7376 TRACE("New params:\n");
7377 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7378 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7379 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7380 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7381 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7382 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7383 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7384 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7385 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7386 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7387 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7388 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7389 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7391 /* No special treatment of these parameters. Just store them */
7392 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7393 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7394 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7395 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7397 /* What to do about these? */
7398 if(pPresentationParameters->BackBufferCount != 0 &&
7399 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7400 ERR("Cannot change the back buffer count yet\n");
7402 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7403 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7404 ERR("Cannot change the back buffer format yet\n");
7406 if(pPresentationParameters->hDeviceWindow != NULL &&
7407 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7408 ERR("Cannot change the device window yet\n");
7410 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7411 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7412 return WINED3DERR_INVALIDCALL;
7415 /* Reset the depth stencil */
7416 if (pPresentationParameters->EnableAutoDepthStencil)
7417 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7418 else
7419 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7421 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7423 if(pPresentationParameters->Windowed) {
7424 mode.Width = swapchain->orig_width;
7425 mode.Height = swapchain->orig_height;
7426 mode.RefreshRate = 0;
7427 mode.Format = swapchain->presentParms.BackBufferFormat;
7428 } else {
7429 mode.Width = pPresentationParameters->BackBufferWidth;
7430 mode.Height = pPresentationParameters->BackBufferHeight;
7431 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7432 mode.Format = swapchain->presentParms.BackBufferFormat;
7435 /* Should Width == 800 && Height == 0 set 800x600? */
7436 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7437 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7438 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7440 UINT i;
7442 if(!pPresentationParameters->Windowed) {
7443 DisplayModeChanged = TRUE;
7445 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7446 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7448 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7449 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7450 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7452 if(This->auto_depth_stencil_buffer) {
7453 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7457 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7458 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7459 DisplayModeChanged) {
7461 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7463 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7464 if(swapchain->presentParms.Windowed) {
7465 /* switch from windowed to fs */
7466 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7467 pPresentationParameters->BackBufferWidth,
7468 pPresentationParameters->BackBufferHeight);
7469 } else {
7470 /* Fullscreen -> fullscreen mode change */
7471 MoveWindow(swapchain->win_handle, 0, 0,
7472 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7473 TRUE);
7475 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7476 /* Fullscreen -> windowed switch */
7477 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7479 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7480 } else if(!pPresentationParameters->Windowed) {
7481 DWORD style = This->style, exStyle = This->exStyle;
7482 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7483 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7484 * Reset to clear up their mess. Guild Wars also loses the device during that.
7486 This->style = 0;
7487 This->exStyle = 0;
7488 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7489 pPresentationParameters->BackBufferWidth,
7490 pPresentationParameters->BackBufferHeight);
7491 This->style = style;
7492 This->exStyle = exStyle;
7495 TRACE("Resetting stateblock\n");
7496 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7497 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7499 /* Note: No parent needed for initial internal stateblock */
7500 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7501 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7502 else TRACE("Created stateblock %p\n", This->stateBlock);
7503 This->updateStateBlock = This->stateBlock;
7504 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7506 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7507 if(FAILED(hr)) {
7508 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7511 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7512 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7514 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7515 * first use
7517 return hr;
7520 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7522 /** FIXME: always true at the moment **/
7523 if(!bEnableDialogs) {
7524 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7526 return WINED3D_OK;
7530 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7532 TRACE("(%p) : pParameters %p\n", This, pParameters);
7534 *pParameters = This->createParms;
7535 return WINED3D_OK;
7538 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7539 IWineD3DSwapChain *swapchain;
7541 TRACE("Relaying to swapchain\n");
7543 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7544 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7545 IWineD3DSwapChain_Release(swapchain);
7547 return;
7550 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7551 IWineD3DSwapChain *swapchain;
7553 TRACE("Relaying to swapchain\n");
7555 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7556 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7557 IWineD3DSwapChain_Release(swapchain);
7559 return;
7563 /** ********************************************************
7564 * Notification functions
7565 ** ********************************************************/
7566 /** This function must be called in the release of a resource when ref == 0,
7567 * the contents of resource must still be correct,
7568 * any handles to other resource held by the caller must be closed
7569 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7570 *****************************************************/
7571 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7574 TRACE("(%p) : Adding Resource %p\n", This, resource);
7575 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7578 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7581 TRACE("(%p) : Removing resource %p\n", This, resource);
7583 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7587 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7589 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7590 int counter;
7592 TRACE("(%p) : resource %p\n", This, resource);
7594 context_resource_released(iface, resource, type);
7596 switch (type) {
7597 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7598 case WINED3DRTYPE_SURFACE: {
7599 unsigned int i;
7601 /* Cleanup any FBO attachments if d3d is enabled */
7602 if(This->d3d_initialized) {
7603 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7604 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7606 TRACE("Last active render target destroyed\n");
7607 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7608 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7609 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7610 * and the lastActiveRenderTarget member shouldn't matter
7612 if(swapchain) {
7613 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7614 TRACE("Activating primary back buffer\n");
7615 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7616 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7617 /* Single buffering environment */
7618 TRACE("Activating primary front buffer\n");
7619 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7620 } else {
7621 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7622 /* Implicit render target destroyed, that means the device is being destroyed
7623 * whatever we set here, it shouldn't matter
7625 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7627 } else {
7628 /* May happen during ddraw uninitialization */
7629 TRACE("Render target set, but swapchain does not exist!\n");
7630 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7634 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7635 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7636 This->render_targets[i] = NULL;
7639 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7640 This->stencilBufferTarget = NULL;
7644 break;
7646 case WINED3DRTYPE_TEXTURE:
7647 case WINED3DRTYPE_CUBETEXTURE:
7648 case WINED3DRTYPE_VOLUMETEXTURE:
7649 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7650 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7651 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7652 This->stateBlock->textures[counter] = NULL;
7654 if (This->updateStateBlock != This->stateBlock ){
7655 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7656 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7657 This->updateStateBlock->textures[counter] = NULL;
7661 break;
7662 case WINED3DRTYPE_VOLUME:
7663 /* TODO: nothing really? */
7664 break;
7665 case WINED3DRTYPE_VERTEXBUFFER:
7667 int streamNumber;
7668 TRACE("Cleaning up stream pointers\n");
7670 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7671 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7672 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7674 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7675 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7676 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7677 This->updateStateBlock->streamSource[streamNumber] = 0;
7678 /* Set changed flag? */
7681 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) */
7682 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7683 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7684 This->stateBlock->streamSource[streamNumber] = 0;
7689 break;
7690 case WINED3DRTYPE_INDEXBUFFER:
7691 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7692 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7693 This->updateStateBlock->pIndexData = NULL;
7696 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7697 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7698 This->stateBlock->pIndexData = NULL;
7701 break;
7703 case WINED3DRTYPE_BUFFER:
7704 /* Nothing to do, yet.*/
7705 break;
7707 default:
7708 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7709 break;
7713 /* Remove the resource from the resourceStore */
7714 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7716 TRACE("Resource released\n");
7720 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7722 IWineD3DResourceImpl *resource, *cursor;
7723 HRESULT ret;
7724 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7726 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7727 TRACE("enumerating resource %p\n", resource);
7728 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7729 ret = pCallback((IWineD3DResource *) resource, pData);
7730 if(ret == S_FALSE) {
7731 TRACE("Canceling enumeration\n");
7732 break;
7735 return WINED3D_OK;
7738 /**********************************************************
7739 * IWineD3DDevice VTbl follows
7740 **********************************************************/
7742 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7744 /*** IUnknown methods ***/
7745 IWineD3DDeviceImpl_QueryInterface,
7746 IWineD3DDeviceImpl_AddRef,
7747 IWineD3DDeviceImpl_Release,
7748 /*** IWineD3DDevice methods ***/
7749 IWineD3DDeviceImpl_GetParent,
7750 /*** Creation methods**/
7751 IWineD3DDeviceImpl_CreateBuffer,
7752 IWineD3DDeviceImpl_CreateVertexBuffer,
7753 IWineD3DDeviceImpl_CreateIndexBuffer,
7754 IWineD3DDeviceImpl_CreateStateBlock,
7755 IWineD3DDeviceImpl_CreateSurface,
7756 IWineD3DDeviceImpl_CreateRendertargetView,
7757 IWineD3DDeviceImpl_CreateTexture,
7758 IWineD3DDeviceImpl_CreateVolumeTexture,
7759 IWineD3DDeviceImpl_CreateVolume,
7760 IWineD3DDeviceImpl_CreateCubeTexture,
7761 IWineD3DDeviceImpl_CreateQuery,
7762 IWineD3DDeviceImpl_CreateSwapChain,
7763 IWineD3DDeviceImpl_CreateVertexDeclaration,
7764 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7765 IWineD3DDeviceImpl_CreateVertexShader,
7766 IWineD3DDeviceImpl_CreatePixelShader,
7767 IWineD3DDeviceImpl_CreatePalette,
7768 /*** Odd functions **/
7769 IWineD3DDeviceImpl_Init3D,
7770 IWineD3DDeviceImpl_InitGDI,
7771 IWineD3DDeviceImpl_Uninit3D,
7772 IWineD3DDeviceImpl_UninitGDI,
7773 IWineD3DDeviceImpl_SetMultithreaded,
7774 IWineD3DDeviceImpl_EvictManagedResources,
7775 IWineD3DDeviceImpl_GetAvailableTextureMem,
7776 IWineD3DDeviceImpl_GetBackBuffer,
7777 IWineD3DDeviceImpl_GetCreationParameters,
7778 IWineD3DDeviceImpl_GetDeviceCaps,
7779 IWineD3DDeviceImpl_GetDirect3D,
7780 IWineD3DDeviceImpl_GetDisplayMode,
7781 IWineD3DDeviceImpl_SetDisplayMode,
7782 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7783 IWineD3DDeviceImpl_GetRasterStatus,
7784 IWineD3DDeviceImpl_GetSwapChain,
7785 IWineD3DDeviceImpl_Reset,
7786 IWineD3DDeviceImpl_SetDialogBoxMode,
7787 IWineD3DDeviceImpl_SetCursorProperties,
7788 IWineD3DDeviceImpl_SetCursorPosition,
7789 IWineD3DDeviceImpl_ShowCursor,
7790 IWineD3DDeviceImpl_TestCooperativeLevel,
7791 /*** Getters and setters **/
7792 IWineD3DDeviceImpl_SetClipPlane,
7793 IWineD3DDeviceImpl_GetClipPlane,
7794 IWineD3DDeviceImpl_SetClipStatus,
7795 IWineD3DDeviceImpl_GetClipStatus,
7796 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7797 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7798 IWineD3DDeviceImpl_SetDepthStencilSurface,
7799 IWineD3DDeviceImpl_GetDepthStencilSurface,
7800 IWineD3DDeviceImpl_SetGammaRamp,
7801 IWineD3DDeviceImpl_GetGammaRamp,
7802 IWineD3DDeviceImpl_SetIndices,
7803 IWineD3DDeviceImpl_GetIndices,
7804 IWineD3DDeviceImpl_SetBaseVertexIndex,
7805 IWineD3DDeviceImpl_GetBaseVertexIndex,
7806 IWineD3DDeviceImpl_SetLight,
7807 IWineD3DDeviceImpl_GetLight,
7808 IWineD3DDeviceImpl_SetLightEnable,
7809 IWineD3DDeviceImpl_GetLightEnable,
7810 IWineD3DDeviceImpl_SetMaterial,
7811 IWineD3DDeviceImpl_GetMaterial,
7812 IWineD3DDeviceImpl_SetNPatchMode,
7813 IWineD3DDeviceImpl_GetNPatchMode,
7814 IWineD3DDeviceImpl_SetPaletteEntries,
7815 IWineD3DDeviceImpl_GetPaletteEntries,
7816 IWineD3DDeviceImpl_SetPixelShader,
7817 IWineD3DDeviceImpl_GetPixelShader,
7818 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7819 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7820 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7821 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7822 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7823 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7824 IWineD3DDeviceImpl_SetRenderState,
7825 IWineD3DDeviceImpl_GetRenderState,
7826 IWineD3DDeviceImpl_SetRenderTarget,
7827 IWineD3DDeviceImpl_GetRenderTarget,
7828 IWineD3DDeviceImpl_SetFrontBackBuffers,
7829 IWineD3DDeviceImpl_SetSamplerState,
7830 IWineD3DDeviceImpl_GetSamplerState,
7831 IWineD3DDeviceImpl_SetScissorRect,
7832 IWineD3DDeviceImpl_GetScissorRect,
7833 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7834 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7835 IWineD3DDeviceImpl_SetStreamSource,
7836 IWineD3DDeviceImpl_GetStreamSource,
7837 IWineD3DDeviceImpl_SetStreamSourceFreq,
7838 IWineD3DDeviceImpl_GetStreamSourceFreq,
7839 IWineD3DDeviceImpl_SetTexture,
7840 IWineD3DDeviceImpl_GetTexture,
7841 IWineD3DDeviceImpl_SetTextureStageState,
7842 IWineD3DDeviceImpl_GetTextureStageState,
7843 IWineD3DDeviceImpl_SetTransform,
7844 IWineD3DDeviceImpl_GetTransform,
7845 IWineD3DDeviceImpl_SetVertexDeclaration,
7846 IWineD3DDeviceImpl_GetVertexDeclaration,
7847 IWineD3DDeviceImpl_SetVertexShader,
7848 IWineD3DDeviceImpl_GetVertexShader,
7849 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7850 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7851 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7852 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7853 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7854 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7855 IWineD3DDeviceImpl_SetViewport,
7856 IWineD3DDeviceImpl_GetViewport,
7857 IWineD3DDeviceImpl_MultiplyTransform,
7858 IWineD3DDeviceImpl_ValidateDevice,
7859 IWineD3DDeviceImpl_ProcessVertices,
7860 /*** State block ***/
7861 IWineD3DDeviceImpl_BeginStateBlock,
7862 IWineD3DDeviceImpl_EndStateBlock,
7863 /*** Scene management ***/
7864 IWineD3DDeviceImpl_BeginScene,
7865 IWineD3DDeviceImpl_EndScene,
7866 IWineD3DDeviceImpl_Present,
7867 IWineD3DDeviceImpl_Clear,
7868 IWineD3DDeviceImpl_ClearRendertargetView,
7869 /*** Drawing ***/
7870 IWineD3DDeviceImpl_SetPrimitiveType,
7871 IWineD3DDeviceImpl_GetPrimitiveType,
7872 IWineD3DDeviceImpl_DrawPrimitive,
7873 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7874 IWineD3DDeviceImpl_DrawPrimitiveUP,
7875 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7876 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7877 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7878 IWineD3DDeviceImpl_DrawRectPatch,
7879 IWineD3DDeviceImpl_DrawTriPatch,
7880 IWineD3DDeviceImpl_DeletePatch,
7881 IWineD3DDeviceImpl_ColorFill,
7882 IWineD3DDeviceImpl_UpdateTexture,
7883 IWineD3DDeviceImpl_UpdateSurface,
7884 IWineD3DDeviceImpl_GetFrontBufferData,
7885 /*** object tracking ***/
7886 IWineD3DDeviceImpl_ResourceReleased,
7887 IWineD3DDeviceImpl_EnumResources
7890 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7891 WINED3DRS_ALPHABLENDENABLE ,
7892 WINED3DRS_ALPHAFUNC ,
7893 WINED3DRS_ALPHAREF ,
7894 WINED3DRS_ALPHATESTENABLE ,
7895 WINED3DRS_BLENDOP ,
7896 WINED3DRS_COLORWRITEENABLE ,
7897 WINED3DRS_DESTBLEND ,
7898 WINED3DRS_DITHERENABLE ,
7899 WINED3DRS_FILLMODE ,
7900 WINED3DRS_FOGDENSITY ,
7901 WINED3DRS_FOGEND ,
7902 WINED3DRS_FOGSTART ,
7903 WINED3DRS_LASTPIXEL ,
7904 WINED3DRS_SHADEMODE ,
7905 WINED3DRS_SRCBLEND ,
7906 WINED3DRS_STENCILENABLE ,
7907 WINED3DRS_STENCILFAIL ,
7908 WINED3DRS_STENCILFUNC ,
7909 WINED3DRS_STENCILMASK ,
7910 WINED3DRS_STENCILPASS ,
7911 WINED3DRS_STENCILREF ,
7912 WINED3DRS_STENCILWRITEMASK ,
7913 WINED3DRS_STENCILZFAIL ,
7914 WINED3DRS_TEXTUREFACTOR ,
7915 WINED3DRS_WRAP0 ,
7916 WINED3DRS_WRAP1 ,
7917 WINED3DRS_WRAP2 ,
7918 WINED3DRS_WRAP3 ,
7919 WINED3DRS_WRAP4 ,
7920 WINED3DRS_WRAP5 ,
7921 WINED3DRS_WRAP6 ,
7922 WINED3DRS_WRAP7 ,
7923 WINED3DRS_ZENABLE ,
7924 WINED3DRS_ZFUNC ,
7925 WINED3DRS_ZWRITEENABLE
7928 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7929 WINED3DTSS_ALPHAARG0 ,
7930 WINED3DTSS_ALPHAARG1 ,
7931 WINED3DTSS_ALPHAARG2 ,
7932 WINED3DTSS_ALPHAOP ,
7933 WINED3DTSS_BUMPENVLOFFSET ,
7934 WINED3DTSS_BUMPENVLSCALE ,
7935 WINED3DTSS_BUMPENVMAT00 ,
7936 WINED3DTSS_BUMPENVMAT01 ,
7937 WINED3DTSS_BUMPENVMAT10 ,
7938 WINED3DTSS_BUMPENVMAT11 ,
7939 WINED3DTSS_COLORARG0 ,
7940 WINED3DTSS_COLORARG1 ,
7941 WINED3DTSS_COLORARG2 ,
7942 WINED3DTSS_COLOROP ,
7943 WINED3DTSS_RESULTARG ,
7944 WINED3DTSS_TEXCOORDINDEX ,
7945 WINED3DTSS_TEXTURETRANSFORMFLAGS
7948 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7949 WINED3DSAMP_ADDRESSU ,
7950 WINED3DSAMP_ADDRESSV ,
7951 WINED3DSAMP_ADDRESSW ,
7952 WINED3DSAMP_BORDERCOLOR ,
7953 WINED3DSAMP_MAGFILTER ,
7954 WINED3DSAMP_MINFILTER ,
7955 WINED3DSAMP_MIPFILTER ,
7956 WINED3DSAMP_MIPMAPLODBIAS ,
7957 WINED3DSAMP_MAXMIPLEVEL ,
7958 WINED3DSAMP_MAXANISOTROPY ,
7959 WINED3DSAMP_SRGBTEXTURE ,
7960 WINED3DSAMP_ELEMENTINDEX
7963 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7964 WINED3DRS_AMBIENT ,
7965 WINED3DRS_AMBIENTMATERIALSOURCE ,
7966 WINED3DRS_CLIPPING ,
7967 WINED3DRS_CLIPPLANEENABLE ,
7968 WINED3DRS_COLORVERTEX ,
7969 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7970 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7971 WINED3DRS_FOGDENSITY ,
7972 WINED3DRS_FOGEND ,
7973 WINED3DRS_FOGSTART ,
7974 WINED3DRS_FOGTABLEMODE ,
7975 WINED3DRS_FOGVERTEXMODE ,
7976 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7977 WINED3DRS_LIGHTING ,
7978 WINED3DRS_LOCALVIEWER ,
7979 WINED3DRS_MULTISAMPLEANTIALIAS ,
7980 WINED3DRS_MULTISAMPLEMASK ,
7981 WINED3DRS_NORMALIZENORMALS ,
7982 WINED3DRS_PATCHEDGESTYLE ,
7983 WINED3DRS_POINTSCALE_A ,
7984 WINED3DRS_POINTSCALE_B ,
7985 WINED3DRS_POINTSCALE_C ,
7986 WINED3DRS_POINTSCALEENABLE ,
7987 WINED3DRS_POINTSIZE ,
7988 WINED3DRS_POINTSIZE_MAX ,
7989 WINED3DRS_POINTSIZE_MIN ,
7990 WINED3DRS_POINTSPRITEENABLE ,
7991 WINED3DRS_RANGEFOGENABLE ,
7992 WINED3DRS_SPECULARMATERIALSOURCE ,
7993 WINED3DRS_TWEENFACTOR ,
7994 WINED3DRS_VERTEXBLEND ,
7995 WINED3DRS_CULLMODE ,
7996 WINED3DRS_FOGCOLOR
7999 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8000 WINED3DTSS_TEXCOORDINDEX ,
8001 WINED3DTSS_TEXTURETRANSFORMFLAGS
8004 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8005 WINED3DSAMP_DMAPOFFSET
8008 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8009 DWORD rep = This->StateTable[state].representative;
8010 DWORD idx;
8011 BYTE shift;
8012 UINT i;
8013 WineD3DContext *context;
8015 if(!rep) return;
8016 for(i = 0; i < This->numContexts; i++) {
8017 context = This->contexts[i];
8018 if(isStateDirty(context, rep)) continue;
8020 context->dirtyArray[context->numDirtyEntries++] = rep;
8021 idx = rep >> 5;
8022 shift = rep & 0x1f;
8023 context->isStateDirty[idx] |= (1 << shift);
8027 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8028 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8029 /* The drawable size of a pbuffer render target is the current pbuffer size
8031 *width = dev->pbufferWidth;
8032 *height = dev->pbufferHeight;
8035 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8036 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8038 *width = This->pow2Width;
8039 *height = This->pow2Height;
8042 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8043 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8044 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8045 * current context's drawable, which is the size of the back buffer of the swapchain
8046 * the active context belongs to. The back buffer of the swapchain is stored as the
8047 * surface the context belongs to.
8049 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8050 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;