push eb25bf65c4616aa55a810ed5c29198b1a080b208
[wine/hacks.git] / dlls / wined3d / device.c
blob63f7352a7364ede7545f26bcd4ffa2359a2d9082
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), 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 struct wined3d_buffer *object;
266 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
267 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
268 HRESULT hr;
269 BOOL conv;
271 if(Size == 0) {
272 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
273 *ppVertexBuffer = NULL;
274 return WINED3DERR_INVALIDCALL;
275 } else if(Pool == WINED3DPOOL_SCRATCH) {
276 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
277 * anyway, SCRATCH vertex buffers aren't usable anywhere
279 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
280 *ppVertexBuffer = NULL;
281 return WINED3DERR_INVALIDCALL;
284 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
285 if (!object)
287 ERR("Out of memory\n");
288 *ppVertexBuffer = NULL;
289 return WINED3DERR_OUTOFVIDEOMEMORY;
292 object->vtbl = &wined3d_buffer_vtbl;
293 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, Format, Pool, parent);
294 if (FAILED(hr))
296 WARN("Failed to initialize resource, returning %#x\n", hr);
297 HeapFree(GetProcessHeap(), 0, object);
298 *ppVertexBuffer = NULL;
299 return hr;
302 TRACE("(%p) : Created resource %p\n", This, object);
304 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
306 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);
307 *ppVertexBuffer = (IWineD3DBuffer *)object;
309 object->fvf = FVF;
311 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
312 * drawStridedFast (half-life 2).
314 * Basically converting the vertices in the buffer is quite expensive, and observations
315 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
316 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
318 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
319 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
320 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
321 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
322 * dx7 apps.
323 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
324 * more. In this call we can convert dx7 buffers too.
326 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
327 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
329 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
330 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
331 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
332 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
333 } else if(dxVersion <= 7 && conv) {
334 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
335 } else {
336 object->flags |= WINED3D_BUFFER_CREATEBO;
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 HRESULT hr;
398 TRACE("(%p) Creating index buffer\n", This);
400 /* Allocate the storage for the device */
401 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
402 if (!object)
404 ERR("Out of memory\n");
405 *ppIndexBuffer = NULL;
406 return WINED3DERR_OUTOFVIDEOMEMORY;
409 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
410 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, Format, Pool, parent);
411 if (FAILED(hr))
413 WARN("Failed to initialize resource, returning %#x\n", hr);
414 HeapFree(GetProcessHeap(), 0, object);
415 *ppIndexBuffer = NULL;
416 return hr;
419 TRACE("(%p) : Created resource %p\n", This, object);
421 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
423 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
424 CreateIndexBufferVBO(This, object);
427 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
428 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
429 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
431 return WINED3D_OK;
434 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DStateBlockImpl *object;
438 int i, j;
439 HRESULT temp_result;
441 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
442 if(!object)
444 ERR("Out of memory\n");
445 *ppStateBlock = NULL;
446 return WINED3DERR_OUTOFVIDEOMEMORY;
449 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
450 object->wineD3DDevice = This;
451 object->parent = parent;
452 object->ref = 1;
453 object->blockType = Type;
455 *ppStateBlock = (IWineD3DStateBlock *)object;
457 for(i = 0; i < LIGHTMAP_SIZE; i++) {
458 list_init(&object->lightMap[i]);
461 temp_result = allocate_shader_constants(object);
462 if (FAILED(temp_result))
464 HeapFree(GetProcessHeap(), 0, object);
465 return temp_result;
468 /* Special case - Used during initialization to produce a placeholder stateblock
469 so other functions called can update a state block */
470 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
472 /* Don't bother increasing the reference count otherwise a device will never
473 be freed due to circular dependencies */
474 return WINED3D_OK;
477 /* Otherwise, might as well set the whole state block to the appropriate values */
478 if (This->stateBlock != NULL)
479 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
480 else
481 memset(object->streamFreq, 1, sizeof(object->streamFreq));
483 /* Reset the ref and type after kludging it */
484 object->wineD3DDevice = This;
485 object->ref = 1;
486 object->blockType = Type;
488 TRACE("Updating changed flags appropriate for type %d\n", Type);
490 if (Type == WINED3DSBT_ALL) {
492 TRACE("ALL => Pretend everything has changed\n");
493 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
495 /* Lights are not part of the changed / set structure */
496 for(j = 0; j < LIGHTMAP_SIZE; j++) {
497 struct list *e;
498 LIST_FOR_EACH(e, &object->lightMap[j]) {
499 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
500 light->changed = TRUE;
501 light->enabledChanged = TRUE;
504 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
505 object->contained_render_states[j - 1] = j;
507 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
508 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
509 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
510 object->contained_transform_states[j - 1] = j;
512 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
513 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
514 object->contained_vs_consts_f[j] = j;
516 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
517 for(j = 0; j < MAX_CONST_I; j++) {
518 object->contained_vs_consts_i[j] = j;
520 object->num_contained_vs_consts_i = MAX_CONST_I;
521 for(j = 0; j < MAX_CONST_B; j++) {
522 object->contained_vs_consts_b[j] = j;
524 object->num_contained_vs_consts_b = MAX_CONST_B;
525 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
526 object->contained_ps_consts_f[j] = j;
528 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
529 for(j = 0; j < MAX_CONST_I; j++) {
530 object->contained_ps_consts_i[j] = j;
532 object->num_contained_ps_consts_i = MAX_CONST_I;
533 for(j = 0; j < MAX_CONST_B; j++) {
534 object->contained_ps_consts_b[j] = j;
536 object->num_contained_ps_consts_b = MAX_CONST_B;
537 for(i = 0; i < MAX_TEXTURES; i++) {
538 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
540 object->contained_tss_states[object->num_contained_tss_states].stage = i;
541 object->contained_tss_states[object->num_contained_tss_states].state = j;
542 object->num_contained_tss_states++;
545 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
546 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
547 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
548 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
549 object->num_contained_sampler_states++;
553 for(i = 0; i < MAX_STREAMS; i++) {
554 if(object->streamSource[i]) {
555 IWineD3DBuffer_AddRef(object->streamSource[i]);
558 if(object->pIndexData) {
559 IWineD3DIndexBuffer_AddRef(object->pIndexData);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 if(object->pixelShader) {
565 IWineD3DPixelShader_AddRef(object->pixelShader);
568 } else if (Type == WINED3DSBT_PIXELSTATE) {
570 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
571 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
573 object->changed.pixelShader = TRUE;
575 /* Pixel Shader Constants */
576 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
577 object->contained_ps_consts_f[i] = i;
578 object->changed.pixelShaderConstantsF[i] = TRUE;
580 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
581 for (i = 0; i < MAX_CONST_B; ++i) {
582 object->contained_ps_consts_b[i] = i;
583 object->changed.pixelShaderConstantsB |= (1 << i);
585 object->num_contained_ps_consts_b = MAX_CONST_B;
586 for (i = 0; i < MAX_CONST_I; ++i) {
587 object->contained_ps_consts_i[i] = i;
588 object->changed.pixelShaderConstantsI |= (1 << i);
590 object->num_contained_ps_consts_i = MAX_CONST_I;
592 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
593 DWORD rs = SavedPixelStates_R[i];
594 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
595 object->contained_render_states[i] = rs;
597 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
598 for (j = 0; j < MAX_TEXTURES; j++) {
599 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
600 DWORD state = SavedPixelStates_T[i];
601 object->changed.textureState[j] |= 1 << state;
602 object->contained_tss_states[object->num_contained_tss_states].stage = j;
603 object->contained_tss_states[object->num_contained_tss_states].state = state;
604 object->num_contained_tss_states++;
607 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
608 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
609 DWORD state = SavedPixelStates_S[i];
610 object->changed.samplerState[j] |= 1 << state;
611 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
612 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
613 object->num_contained_sampler_states++;
616 if(object->pixelShader) {
617 IWineD3DPixelShader_AddRef(object->pixelShader);
620 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
621 * on them. This makes releasing the buffer easier
623 for(i = 0; i < MAX_STREAMS; i++) {
624 object->streamSource[i] = NULL;
626 object->pIndexData = NULL;
627 object->vertexShader = NULL;
629 } else if (Type == WINED3DSBT_VERTEXSTATE) {
631 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
632 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
634 object->changed.vertexShader = TRUE;
636 /* Vertex Shader Constants */
637 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
638 object->changed.vertexShaderConstantsF[i] = TRUE;
639 object->contained_vs_consts_f[i] = i;
641 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
642 for (i = 0; i < MAX_CONST_B; ++i) {
643 object->contained_vs_consts_b[i] = i;
644 object->changed.vertexShaderConstantsB |= (1 << i);
646 object->num_contained_vs_consts_b = MAX_CONST_B;
647 for (i = 0; i < MAX_CONST_I; ++i) {
648 object->contained_vs_consts_i[i] = i;
649 object->changed.vertexShaderConstantsI |= (1 << i);
651 object->num_contained_vs_consts_i = MAX_CONST_I;
652 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
653 DWORD rs = SavedVertexStates_R[i];
654 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
655 object->contained_render_states[i] = rs;
657 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
658 for (j = 0; j < MAX_TEXTURES; j++) {
659 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
660 DWORD state = SavedVertexStates_T[i];
661 object->changed.textureState[j] |= 1 << state;
662 object->contained_tss_states[object->num_contained_tss_states].stage = j;
663 object->contained_tss_states[object->num_contained_tss_states].state = state;
664 object->num_contained_tss_states++;
667 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
668 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
669 DWORD state = SavedVertexStates_S[i];
670 object->changed.samplerState[j] |= 1 << state;
671 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
672 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
673 object->num_contained_sampler_states++;
677 for(j = 0; j < LIGHTMAP_SIZE; j++) {
678 struct list *e;
679 LIST_FOR_EACH(e, &object->lightMap[j]) {
680 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
681 light->changed = TRUE;
682 light->enabledChanged = TRUE;
686 for(i = 0; i < MAX_STREAMS; i++) {
687 if(object->streamSource[i]) {
688 IWineD3DBuffer_AddRef(object->streamSource[i]);
691 if(object->vertexShader) {
692 IWineD3DVertexShader_AddRef(object->vertexShader);
694 object->pIndexData = NULL;
695 object->pixelShader = NULL;
696 } else {
697 FIXME("Unrecognized state block type %d\n", Type);
700 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
701 return WINED3D_OK;
704 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) {
705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
706 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
707 unsigned int Size = 1;
708 const struct GlPixelFormatDesc *glDesc;
709 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
710 UINT mul_4w, mul_4h;
711 HRESULT hr;
713 TRACE("(%p) Create surface\n",This);
715 if(MultisampleQuality > 0) {
716 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
717 MultisampleQuality=0;
720 /** FIXME: Check that the format is supported
721 * by the device.
722 *******************************/
724 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
725 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
726 * space!
727 *********************************/
728 mul_4w = (Width + 3) & ~3;
729 mul_4h = (Height + 3) & ~3;
730 if (WINED3DFMT_UNKNOWN == Format) {
731 Size = 0;
732 } else if (Format == WINED3DFMT_DXT1) {
733 /* DXT1 is half byte per pixel */
734 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
736 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
737 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
738 Format == WINED3DFMT_ATI2N) {
739 Size = (mul_4w * tableEntry->bpp * mul_4h);
740 } else {
741 /* The pitch is a multiple of 4 bytes */
742 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
743 Size *= Height;
746 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
748 /** Create and initialise the surface resource **/
749 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
750 if (!object)
752 ERR("Out of memory\n");
753 *ppSurface = NULL;
754 return WINED3DERR_OUTOFVIDEOMEMORY;
757 /* Look at the implementation and set the correct Vtable */
758 switch(Impl)
760 case SURFACE_OPENGL:
761 /* Check if a 3D adapter is available when creating gl surfaces */
762 if (!This->adapter)
764 ERR("OpenGL surfaces are not available without opengl\n");
765 HeapFree(GetProcessHeap(), 0, object);
766 return WINED3DERR_NOTAVAILABLE;
768 object->lpVtbl = &IWineD3DSurface_Vtbl;
769 break;
771 case SURFACE_GDI:
772 object->lpVtbl = &IWineGDISurface_Vtbl;
773 break;
775 default:
776 /* To be sure to catch this */
777 ERR("Unknown requested surface implementation %d!\n", Impl);
778 HeapFree(GetProcessHeap(), 0, object);
779 return WINED3DERR_INVALIDCALL;
782 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, Format, Pool, parent);
783 if (FAILED(hr))
785 WARN("Failed to initialize resource, returning %#x\n", hr);
786 HeapFree(GetProcessHeap(), 0, object);
787 *ppSurface = NULL;
788 return hr;
791 TRACE("(%p) : Created resource %p\n", This, object);
793 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
795 *ppSurface = (IWineD3DSurface *)object;
797 /* "Standalone" surface */
798 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
800 object->currentDesc.Width = Width;
801 object->currentDesc.Height = Height;
802 object->currentDesc.MultiSampleType = MultiSample;
803 object->currentDesc.MultiSampleQuality = MultisampleQuality;
804 object->glDescription.level = Level;
805 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
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 = tableEntry->bpp;
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 IWineD3DTextureImpl *object;
908 unsigned int i;
909 UINT tmpW;
910 UINT tmpH;
911 HRESULT hr;
912 unsigned int pow2Width;
913 unsigned int pow2Height;
914 const struct GlPixelFormatDesc *glDesc;
915 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
917 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
918 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
919 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN >= Format) {
924 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
925 return WINED3DERR_INVALIDCALL;
928 /* Non-power2 support */
929 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
931 pow2Width = Width;
932 pow2Height = Height;
934 else
936 /* Find the nearest pow2 match */
937 pow2Width = pow2Height = 1;
938 while (pow2Width < Width) pow2Width <<= 1;
939 while (pow2Height < Height) pow2Height <<= 1;
941 if (pow2Width != Width || pow2Height != Height)
943 if (Levels > 1)
945 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
946 return WINED3DERR_INVALIDCALL;
948 Levels = 1;
952 /* Calculate levels for mip mapping */
953 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
955 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
957 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
958 return WINED3DERR_INVALIDCALL;
961 if (Levels > 1)
963 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL;
967 Levels = 1;
969 else if (!Levels)
971 Levels = wined3d_log2i(max(Width, Height)) + 1;
972 TRACE("Calculated levels = %d\n", Levels);
975 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
976 if (!object)
978 ERR("Out of memory\n");
979 *ppTexture = NULL;
980 return WINED3DERR_OUTOFVIDEOMEMORY;
983 object->lpVtbl = &IWineD3DTexture_Vtbl;
984 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
985 if (FAILED(hr))
987 WARN("Failed to initialize resource, returning %#x\n", hr);
988 HeapFree(GetProcessHeap(), 0, object);
989 *ppTexture = NULL;
990 return hr;
993 TRACE("(%p) : Created resource %p\n", This, object);
995 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
997 *ppTexture = (IWineD3DTexture *)object;
999 basetexture_init(&object->baseTexture, Levels, Usage);
1000 object->width = Width;
1001 object->height = Height;
1003 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1004 object->baseTexture.minMipLookup = minMipLookup;
1005 object->baseTexture.magLookup = magLookup;
1006 } else {
1007 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1008 object->baseTexture.magLookup = magLookup_noFilter;
1011 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1012 /* Precalculated scaling for 'faked' non power of two texture coords.
1013 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1014 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1015 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1017 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1018 object->baseTexture.pow2Matrix[0] = 1.0;
1019 object->baseTexture.pow2Matrix[5] = 1.0;
1020 object->baseTexture.pow2Matrix[10] = 1.0;
1021 object->baseTexture.pow2Matrix[15] = 1.0;
1022 object->target = GL_TEXTURE_2D;
1023 object->cond_np2 = TRUE;
1024 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1025 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1026 (Width != pow2Width || Height != pow2Height) &&
1027 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1029 object->baseTexture.pow2Matrix[0] = (float)Width;
1030 object->baseTexture.pow2Matrix[5] = (float)Height;
1031 object->baseTexture.pow2Matrix[10] = 1.0;
1032 object->baseTexture.pow2Matrix[15] = 1.0;
1033 object->target = GL_TEXTURE_RECTANGLE_ARB;
1034 object->cond_np2 = TRUE;
1035 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1036 } else {
1037 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1038 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1039 object->baseTexture.pow2Matrix[10] = 1.0;
1040 object->baseTexture.pow2Matrix[15] = 1.0;
1041 object->target = GL_TEXTURE_2D;
1042 object->cond_np2 = FALSE;
1044 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1046 /* Generate all the surfaces */
1047 tmpW = Width;
1048 tmpH = Height;
1049 for (i = 0; i < object->baseTexture.levels; i++)
1051 /* use the callback to create the texture surface */
1052 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1053 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1054 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1055 FIXME("Failed to create surface %p\n", object);
1056 /* clean up */
1057 object->surfaces[i] = NULL;
1058 IWineD3DTexture_Release((IWineD3DTexture *)object);
1060 *ppTexture = NULL;
1061 return hr;
1064 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1065 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1066 surface_set_texture_target(object->surfaces[i], object->target);
1067 /* calculate the next mipmap level */
1068 tmpW = max(1, tmpW >> 1);
1069 tmpH = max(1, tmpH >> 1);
1071 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1072 object->baseTexture.internal_preload = texture_internal_preload;
1074 TRACE("(%p) : Created texture %p\n", This, object);
1075 return WINED3D_OK;
1078 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1079 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1080 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1083 IWineD3DVolumeTextureImpl *object;
1084 unsigned int i;
1085 UINT tmpW;
1086 UINT tmpH;
1087 UINT tmpD;
1088 const struct GlPixelFormatDesc *glDesc;
1089 HRESULT hr;
1091 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1093 /* TODO: It should only be possible to create textures for formats
1094 that are reported as supported */
1095 if (WINED3DFMT_UNKNOWN >= Format) {
1096 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1097 return WINED3DERR_INVALIDCALL;
1099 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1100 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1101 return WINED3DERR_INVALIDCALL;
1104 /* Calculate levels for mip mapping */
1105 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1107 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1109 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1110 return WINED3DERR_INVALIDCALL;
1113 if (Levels > 1)
1115 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1116 return WINED3DERR_INVALIDCALL;
1119 Levels = 1;
1121 else if (!Levels)
1123 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1124 TRACE("Calculated levels = %d\n", Levels);
1127 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1128 if (!object)
1130 ERR("Out of memory\n");
1131 *ppVolumeTexture = NULL;
1132 return WINED3DERR_OUTOFVIDEOMEMORY;
1135 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1136 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, Format, Pool, parent);
1137 if (FAILED(hr))
1139 WARN("Failed to initialize resource, returning %#x\n", hr);
1140 HeapFree(GetProcessHeap(), 0, object);
1141 *ppVolumeTexture = NULL;
1142 return hr;
1145 TRACE("(%p) : Created resource %p\n", This, object);
1147 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1149 basetexture_init(&object->baseTexture, Levels, Usage);
1151 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1152 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1154 /* Is NP2 support for volumes needed? */
1155 object->baseTexture.pow2Matrix[ 0] = 1.0;
1156 object->baseTexture.pow2Matrix[ 5] = 1.0;
1157 object->baseTexture.pow2Matrix[10] = 1.0;
1158 object->baseTexture.pow2Matrix[15] = 1.0;
1160 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1161 object->baseTexture.minMipLookup = minMipLookup;
1162 object->baseTexture.magLookup = magLookup;
1163 } else {
1164 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1165 object->baseTexture.magLookup = magLookup_noFilter;
1168 /* Generate all the surfaces */
1169 tmpW = Width;
1170 tmpH = Height;
1171 tmpD = Depth;
1173 for (i = 0; i < object->baseTexture.levels; i++)
1175 HRESULT hr;
1176 /* Create the volume */
1177 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1178 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1179 if(FAILED(hr)) {
1180 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1181 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1182 *ppVolumeTexture = NULL;
1183 return hr;
1186 /* Set its container to this object */
1187 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1189 /* calculate the next mipmap level */
1190 tmpW = max(1, tmpW >> 1);
1191 tmpH = max(1, tmpH >> 1);
1192 tmpD = max(1, tmpD >> 1);
1194 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1195 object->baseTexture.internal_preload = volumetexture_internal_preload;
1197 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1198 TRACE("(%p) : Created volume texture %p\n", This, object);
1199 return WINED3D_OK;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1203 UINT Width, UINT Height, UINT Depth,
1204 DWORD Usage,
1205 WINED3DFORMAT Format, WINED3DPOOL Pool,
1206 IWineD3DVolume** ppVolume,
1207 HANDLE* pSharedHandle, IUnknown *parent) {
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1210 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1211 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1212 HRESULT hr;
1214 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1215 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1216 return WINED3DERR_INVALIDCALL;
1219 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1220 if (!object)
1222 ERR("Out of memory\n");
1223 *ppVolume = NULL;
1224 return WINED3DERR_OUTOFVIDEOMEMORY;
1227 object->lpVtbl = &IWineD3DVolume_Vtbl;
1228 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1229 Width * Height * Depth * formatDesc->bpp, Usage, Format, Pool, parent);
1230 if (FAILED(hr))
1232 WARN("Failed to initialize resource, returning %#x\n", hr);
1233 HeapFree(GetProcessHeap(), 0, object);
1234 *ppVolume = NULL;
1235 return hr;
1238 TRACE("(%p) : Created resource %p\n", This, object);
1240 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1242 *ppVolume = (IWineD3DVolume *)object;
1244 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1245 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1247 object->currentDesc.Width = Width;
1248 object->currentDesc.Height = Height;
1249 object->currentDesc.Depth = Depth;
1250 object->bytesPerPixel = formatDesc->bpp;
1252 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1253 object->lockable = TRUE;
1254 object->locked = FALSE;
1255 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1256 object->dirty = TRUE;
1258 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1260 return WINED3D_OK;
1263 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1264 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1265 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1268 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1269 unsigned int i, j;
1270 UINT tmpW;
1271 HRESULT hr;
1272 unsigned int pow2EdgeLength;
1273 const struct GlPixelFormatDesc *glDesc;
1274 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1276 /* TODO: It should only be possible to create textures for formats
1277 that are reported as supported */
1278 if (WINED3DFMT_UNKNOWN >= Format) {
1279 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1280 return WINED3DERR_INVALIDCALL;
1283 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1284 WARN("(%p) : Tried to create not supported cube texture\n", This);
1285 return WINED3DERR_INVALIDCALL;
1288 /* Calculate levels for mip mapping */
1289 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1291 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1293 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1294 return WINED3DERR_INVALIDCALL;
1297 if (Levels > 1)
1299 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1300 return WINED3DERR_INVALIDCALL;
1303 Levels = 1;
1305 else if (!Levels)
1307 Levels = wined3d_log2i(EdgeLength) + 1;
1308 TRACE("Calculated levels = %d\n", Levels);
1311 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1312 if (!object)
1314 ERR("Out of memory\n");
1315 *ppCubeTexture = NULL;
1316 return WINED3DERR_OUTOFVIDEOMEMORY;
1319 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1320 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, Format, Pool, parent);
1321 if (FAILED(hr))
1323 WARN("Failed to initialize resource, returning %#x\n", hr);
1324 HeapFree(GetProcessHeap(), 0, object);
1325 *ppCubeTexture = NULL;
1326 return hr;
1329 TRACE("(%p) : Created resource %p\n", This, object);
1331 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1333 basetexture_init(&object->baseTexture, Levels, Usage);
1335 TRACE("(%p) Create Cube Texture\n", This);
1337 /* Find the nearest pow2 match */
1338 pow2EdgeLength = 1;
1339 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1341 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1342 /* Precalculated scaling for 'faked' non power of two texture coords */
1343 object->baseTexture.pow2Matrix[ 0] = 1.0;
1344 object->baseTexture.pow2Matrix[ 5] = 1.0;
1345 object->baseTexture.pow2Matrix[10] = 1.0;
1346 object->baseTexture.pow2Matrix[15] = 1.0;
1347 } else {
1348 /* Precalculated scaling for 'faked' non power of two texture coords */
1349 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1350 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1351 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1352 object->baseTexture.pow2Matrix[15] = 1.0;
1355 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1356 object->baseTexture.minMipLookup = minMipLookup;
1357 object->baseTexture.magLookup = magLookup;
1358 } else {
1359 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1360 object->baseTexture.magLookup = magLookup_noFilter;
1363 /* Generate all the surfaces */
1364 tmpW = EdgeLength;
1365 for (i = 0; i < object->baseTexture.levels; i++) {
1367 /* Create the 6 faces */
1368 for (j = 0; j < 6; j++) {
1369 static const GLenum cube_targets[6] = {
1370 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1371 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1372 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1373 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1374 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1375 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1378 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1379 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1380 if (FAILED(hr))
1382 FIXME("(%p) Failed to create surface\n",object);
1383 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1384 *ppCubeTexture = NULL;
1385 return hr;
1387 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1388 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1389 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1391 tmpW = max(1, tmpW >> 1);
1393 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1394 object->baseTexture.internal_preload = cubetexture_internal_preload;
1396 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1397 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1398 return WINED3D_OK;
1401 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1403 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1404 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1405 const IWineD3DQueryVtbl *vtable;
1407 /* Just a check to see if we support this type of query */
1408 switch(Type) {
1409 case WINED3DQUERYTYPE_OCCLUSION:
1410 TRACE("(%p) occlusion query\n", This);
1411 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1412 hr = WINED3D_OK;
1413 else
1414 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1416 vtable = &IWineD3DOcclusionQuery_Vtbl;
1417 break;
1419 case WINED3DQUERYTYPE_EVENT:
1420 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1421 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1422 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1424 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1426 vtable = &IWineD3DEventQuery_Vtbl;
1427 hr = WINED3D_OK;
1428 break;
1430 case WINED3DQUERYTYPE_VCACHE:
1431 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1432 case WINED3DQUERYTYPE_VERTEXSTATS:
1433 case WINED3DQUERYTYPE_TIMESTAMP:
1434 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1435 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1436 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1437 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1438 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1439 case WINED3DQUERYTYPE_PIXELTIMINGS:
1440 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1441 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1442 default:
1443 /* Use the base Query vtable until we have a special one for each query */
1444 vtable = &IWineD3DQuery_Vtbl;
1445 FIXME("(%p) Unhandled query type %d\n", This, Type);
1447 if(NULL == ppQuery || hr != WINED3D_OK) {
1448 return hr;
1451 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1452 if(!object)
1454 ERR("Out of memory\n");
1455 *ppQuery = NULL;
1456 return WINED3DERR_OUTOFVIDEOMEMORY;
1459 object->lpVtbl = vtable;
1460 object->type = Type;
1461 object->state = QUERY_CREATED;
1462 object->wineD3DDevice = This;
1463 object->parent = parent;
1464 object->ref = 1;
1466 *ppQuery = (IWineD3DQuery *)object;
1468 /* allocated the 'extended' data based on the type of query requested */
1469 switch(Type){
1470 case WINED3DQUERYTYPE_OCCLUSION:
1471 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1472 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1474 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1475 TRACE("(%p) Allocating data for an occlusion query\n", This);
1477 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1478 ENTER_GL();
1479 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1480 LEAVE_GL();
1481 break;
1483 case WINED3DQUERYTYPE_EVENT:
1484 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1485 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1487 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1488 ENTER_GL();
1489 if(GL_SUPPORT(APPLE_FENCE)) {
1490 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1491 checkGLcall("glGenFencesAPPLE");
1492 } else if(GL_SUPPORT(NV_FENCE)) {
1493 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1494 checkGLcall("glGenFencesNV");
1496 LEAVE_GL();
1497 break;
1499 case WINED3DQUERYTYPE_VCACHE:
1500 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1501 case WINED3DQUERYTYPE_VERTEXSTATS:
1502 case WINED3DQUERYTYPE_TIMESTAMP:
1503 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1504 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1505 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1506 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1507 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1508 case WINED3DQUERYTYPE_PIXELTIMINGS:
1509 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1510 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1511 default:
1512 object->extendedData = 0;
1513 FIXME("(%p) Unhandled query type %d\n",This , Type);
1515 TRACE("(%p) : Created Query %p\n", This, object);
1516 return WINED3D_OK;
1519 /*****************************************************************************
1520 * IWineD3DDeviceImpl_SetupFullscreenWindow
1522 * Helper function that modifies a HWND's Style and ExStyle for proper
1523 * fullscreen use.
1525 * Params:
1526 * iface: Pointer to the IWineD3DDevice interface
1527 * window: Window to setup
1529 *****************************************************************************/
1530 static LONG fullscreen_style(LONG orig_style) {
1531 LONG style = orig_style;
1532 style &= ~WS_CAPTION;
1533 style &= ~WS_THICKFRAME;
1535 /* Make sure the window is managed, otherwise we won't get keyboard input */
1536 style |= WS_POPUP | WS_SYSMENU;
1538 return style;
1541 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1542 LONG exStyle = orig_exStyle;
1544 /* Filter out window decorations */
1545 exStyle &= ~WS_EX_WINDOWEDGE;
1546 exStyle &= ~WS_EX_CLIENTEDGE;
1548 return exStyle;
1551 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 LONG style, exStyle;
1555 /* Don't do anything if an original style is stored.
1556 * That shouldn't happen
1558 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1559 if (This->style || This->exStyle) {
1560 ERR("(%p): Want to change the window parameters of HWND %p, but "
1561 "another style is stored for restoration afterwards\n", This, window);
1564 /* Get the parameters and save them */
1565 style = GetWindowLongW(window, GWL_STYLE);
1566 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1567 This->style = style;
1568 This->exStyle = exStyle;
1570 style = fullscreen_style(style);
1571 exStyle = fullscreen_exStyle(exStyle);
1573 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1574 This->style, This->exStyle, style, exStyle);
1576 SetWindowLongW(window, GWL_STYLE, style);
1577 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1579 /* Inform the window about the update. */
1580 SetWindowPos(window, HWND_TOP, 0, 0,
1581 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1584 /*****************************************************************************
1585 * IWineD3DDeviceImpl_RestoreWindow
1587 * Helper function that restores a windows' properties when taking it out
1588 * of fullscreen mode
1590 * Params:
1591 * iface: Pointer to the IWineD3DDevice interface
1592 * window: Window to setup
1594 *****************************************************************************/
1595 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1597 LONG style, exStyle;
1599 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1600 * switch, do nothing
1602 if (!This->style && !This->exStyle) return;
1604 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1605 This, window, This->style, This->exStyle);
1607 style = GetWindowLongW(window, GWL_STYLE);
1608 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1610 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1611 * Some applications change it before calling Reset() when switching between windowed and
1612 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1614 if(style == fullscreen_style(This->style) &&
1615 exStyle == fullscreen_style(This->exStyle)) {
1616 SetWindowLongW(window, GWL_STYLE, This->style);
1617 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1620 /* Delete the old values */
1621 This->style = 0;
1622 This->exStyle = 0;
1624 /* Inform the window about the update */
1625 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1626 0, 0, 0, 0, /* Pos, Size, ignored */
1627 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1630 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1631 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1632 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1633 IUnknown *parent, WINED3DSURFTYPE surface_type)
1635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1637 HDC hDc;
1638 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1639 HRESULT hr;
1640 IUnknown *bufferParent;
1641 BOOL displaymode_set = FALSE;
1642 WINED3DDISPLAYMODE Mode;
1643 const StaticPixelFormatDesc *formatDesc;
1645 TRACE("(%p) : Created Additional Swap Chain\n", This);
1647 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1648 * does a device hold a reference to a swap chain giving them a lifetime of the device
1649 * or does the swap chain notify the device of its destruction.
1650 *******************************/
1652 /* Check the params */
1653 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1654 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1655 return WINED3DERR_INVALIDCALL;
1656 } else if (pPresentationParameters->BackBufferCount > 1) {
1657 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");
1660 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1661 if(!object)
1663 ERR("Out of memory\n");
1664 *ppSwapChain = NULL;
1665 return WINED3DERR_OUTOFVIDEOMEMORY;
1668 switch(surface_type) {
1669 case SURFACE_GDI:
1670 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1671 break;
1672 case SURFACE_OPENGL:
1673 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1674 break;
1675 case SURFACE_UNKNOWN:
1676 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1677 HeapFree(GetProcessHeap(), 0, object);
1678 return WINED3DERR_INVALIDCALL;
1680 object->wineD3DDevice = This;
1681 object->parent = parent;
1682 object->ref = 1;
1684 *ppSwapChain = (IWineD3DSwapChain *)object;
1686 /*********************
1687 * Lookup the window Handle and the relating X window handle
1688 ********************/
1690 /* Setup hwnd we are using, plus which display this equates to */
1691 object->win_handle = pPresentationParameters->hDeviceWindow;
1692 if (!object->win_handle) {
1693 object->win_handle = This->createParms.hFocusWindow;
1695 if(!pPresentationParameters->Windowed && object->win_handle) {
1696 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1697 pPresentationParameters->BackBufferWidth,
1698 pPresentationParameters->BackBufferHeight);
1701 hDc = GetDC(object->win_handle);
1702 TRACE("Using hDc %p\n", hDc);
1704 if (NULL == hDc) {
1705 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1706 return WINED3DERR_NOTAVAILABLE;
1709 /* Get info on the current display setup */
1710 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1711 object->orig_width = Mode.Width;
1712 object->orig_height = Mode.Height;
1713 object->orig_fmt = Mode.Format;
1714 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1716 if (pPresentationParameters->Windowed &&
1717 ((pPresentationParameters->BackBufferWidth == 0) ||
1718 (pPresentationParameters->BackBufferHeight == 0) ||
1719 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1721 RECT Rect;
1722 GetClientRect(object->win_handle, &Rect);
1724 if (pPresentationParameters->BackBufferWidth == 0) {
1725 pPresentationParameters->BackBufferWidth = Rect.right;
1726 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1728 if (pPresentationParameters->BackBufferHeight == 0) {
1729 pPresentationParameters->BackBufferHeight = Rect.bottom;
1730 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1732 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1733 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1734 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1738 /* Put the correct figures in the presentation parameters */
1739 TRACE("Copying across presentation parameters\n");
1740 object->presentParms = *pPresentationParameters;
1742 TRACE("calling rendertarget CB\n");
1743 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1744 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1745 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1746 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1747 if (SUCCEEDED(hr)) {
1748 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1749 if(surface_type == SURFACE_OPENGL) {
1750 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1752 } else {
1753 ERR("Failed to create the front buffer\n");
1754 goto error;
1757 /*********************
1758 * Windowed / Fullscreen
1759 *******************/
1762 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1763 * so we should really check to see if there is a fullscreen swapchain already
1764 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1765 **************************************/
1767 if (!pPresentationParameters->Windowed) {
1768 WINED3DDISPLAYMODE mode;
1771 /* Change the display settings */
1772 mode.Width = pPresentationParameters->BackBufferWidth;
1773 mode.Height = pPresentationParameters->BackBufferHeight;
1774 mode.Format = pPresentationParameters->BackBufferFormat;
1775 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1777 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1778 displaymode_set = TRUE;
1782 * Create an opengl context for the display visual
1783 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1784 * use different properties after that point in time. FIXME: How to handle when requested format
1785 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1786 * it chooses is identical to the one already being used!
1787 **********************************/
1788 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1790 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1791 if(!object->context) {
1792 ERR("Failed to create the context array\n");
1793 hr = E_OUTOFMEMORY;
1794 goto error;
1796 object->num_contexts = 1;
1798 if(surface_type == SURFACE_OPENGL) {
1799 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1800 if (!object->context[0]) {
1801 ERR("Failed to create a new context\n");
1802 hr = WINED3DERR_NOTAVAILABLE;
1803 goto error;
1804 } else {
1805 TRACE("Context created (HWND=%p, glContext=%p)\n",
1806 object->win_handle, object->context[0]->glCtx);
1810 /*********************
1811 * Create the back, front and stencil buffers
1812 *******************/
1813 if(object->presentParms.BackBufferCount > 0) {
1814 UINT i;
1816 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1817 if(!object->backBuffer) {
1818 ERR("Out of memory\n");
1819 hr = E_OUTOFMEMORY;
1820 goto error;
1823 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1824 TRACE("calling rendertarget CB\n");
1825 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1826 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1827 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1828 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1829 if(SUCCEEDED(hr)) {
1830 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1831 } else {
1832 ERR("Cannot create new back buffer\n");
1833 goto error;
1835 if(surface_type == SURFACE_OPENGL) {
1836 ENTER_GL();
1837 glDrawBuffer(GL_BACK);
1838 checkGLcall("glDrawBuffer(GL_BACK)");
1839 LEAVE_GL();
1842 } else {
1843 object->backBuffer = NULL;
1845 /* Single buffering - draw to front buffer */
1846 if(surface_type == SURFACE_OPENGL) {
1847 ENTER_GL();
1848 glDrawBuffer(GL_FRONT);
1849 checkGLcall("glDrawBuffer(GL_FRONT)");
1850 LEAVE_GL();
1854 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1855 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1856 TRACE("Creating depth stencil buffer\n");
1857 if (This->auto_depth_stencil_buffer == NULL ) {
1858 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1859 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1860 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1861 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1862 &This->auto_depth_stencil_buffer);
1863 if (SUCCEEDED(hr)) {
1864 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1865 } else {
1866 ERR("Failed to create the auto depth stencil\n");
1867 goto error;
1872 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1874 TRACE("Created swapchain %p\n", object);
1875 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1876 return WINED3D_OK;
1878 error:
1879 if (displaymode_set) {
1880 DEVMODEW devmode;
1881 RECT clip_rc;
1883 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1884 ClipCursor(NULL);
1886 /* Change the display settings */
1887 memset(&devmode, 0, sizeof(devmode));
1888 devmode.dmSize = sizeof(devmode);
1889 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1890 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1891 devmode.dmPelsWidth = object->orig_width;
1892 devmode.dmPelsHeight = object->orig_height;
1893 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1896 if (object->backBuffer) {
1897 UINT i;
1898 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1899 if(object->backBuffer[i]) {
1900 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1901 IUnknown_Release(bufferParent); /* once for the get parent */
1902 if (IUnknown_Release(bufferParent) > 0) {
1903 FIXME("(%p) Something's still holding the back buffer\n",This);
1907 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1908 object->backBuffer = NULL;
1910 if(object->context && object->context[0])
1911 DestroyContext(This, object->context[0]);
1912 if(object->frontBuffer) {
1913 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1914 IUnknown_Release(bufferParent); /* once for the get parent */
1915 if (IUnknown_Release(bufferParent) > 0) {
1916 FIXME("(%p) Something's still holding the front buffer\n",This);
1919 HeapFree(GetProcessHeap(), 0, object);
1920 return hr;
1923 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1924 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 TRACE("(%p)\n", This);
1928 return This->NumberOfSwapChains;
1931 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1933 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1935 if(iSwapChain < This->NumberOfSwapChains) {
1936 *pSwapChain = This->swapchains[iSwapChain];
1937 IWineD3DSwapChain_AddRef(*pSwapChain);
1938 TRACE("(%p) returning %p\n", This, *pSwapChain);
1939 return WINED3D_OK;
1940 } else {
1941 TRACE("Swapchain out of range\n");
1942 *pSwapChain = NULL;
1943 return WINED3DERR_INVALIDCALL;
1947 /*****
1948 * Vertex Declaration
1949 *****/
1950 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1951 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1953 IWineD3DVertexDeclarationImpl *object = NULL;
1954 HRESULT hr = WINED3D_OK;
1956 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1957 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1959 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1960 if(!object)
1962 ERR("Out of memory\n");
1963 *ppVertexDeclaration = NULL;
1964 return WINED3DERR_OUTOFVIDEOMEMORY;
1967 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1968 object->wineD3DDevice = This;
1969 object->parent = parent;
1970 object->ref = 1;
1972 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1974 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1975 if(FAILED(hr)) {
1976 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1977 *ppVertexDeclaration = NULL;
1980 return hr;
1983 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1984 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1986 unsigned int idx, idx2;
1987 unsigned int offset;
1988 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1989 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1990 BOOL has_blend_idx = has_blend &&
1991 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1992 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1993 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1994 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1995 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1996 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1997 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1999 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2000 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2002 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
2003 WINED3DVERTEXELEMENT *elements = NULL;
2005 unsigned int size;
2006 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2007 if (has_blend_idx) num_blends--;
2009 /* Compute declaration size */
2010 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2011 has_psize + has_diffuse + has_specular + num_textures + 1;
2013 /* convert the declaration */
2014 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2015 if (!elements)
2016 return 0;
2018 elements[size-1] = end_element;
2019 idx = 0;
2020 if (has_pos) {
2021 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2022 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2023 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2025 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2026 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2027 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2029 else {
2030 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2031 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2033 elements[idx].UsageIndex = 0;
2034 idx++;
2036 if (has_blend && (num_blends > 0)) {
2037 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2038 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2039 else {
2040 switch(num_blends) {
2041 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2042 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2043 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2044 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2045 default:
2046 ERR("Unexpected amount of blend values: %u\n", num_blends);
2049 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2050 elements[idx].UsageIndex = 0;
2051 idx++;
2053 if (has_blend_idx) {
2054 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2055 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2056 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2057 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2058 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2059 else
2060 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2061 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2062 elements[idx].UsageIndex = 0;
2063 idx++;
2065 if (has_normal) {
2066 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2067 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2068 elements[idx].UsageIndex = 0;
2069 idx++;
2071 if (has_psize) {
2072 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2073 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2074 elements[idx].UsageIndex = 0;
2075 idx++;
2077 if (has_diffuse) {
2078 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2079 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2080 elements[idx].UsageIndex = 0;
2081 idx++;
2083 if (has_specular) {
2084 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2085 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2086 elements[idx].UsageIndex = 1;
2087 idx++;
2089 for (idx2 = 0; idx2 < num_textures; idx2++) {
2090 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2091 switch (numcoords) {
2092 case WINED3DFVF_TEXTUREFORMAT1:
2093 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2094 break;
2095 case WINED3DFVF_TEXTUREFORMAT2:
2096 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2097 break;
2098 case WINED3DFVF_TEXTUREFORMAT3:
2099 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2100 break;
2101 case WINED3DFVF_TEXTUREFORMAT4:
2102 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2103 break;
2105 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2106 elements[idx].UsageIndex = idx2;
2107 idx++;
2110 /* Now compute offsets, and initialize the rest of the fields */
2111 for (idx = 0, offset = 0; idx < size-1; idx++) {
2112 elements[idx].Stream = 0;
2113 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2114 elements[idx].Offset = offset;
2115 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2118 *ppVertexElements = elements;
2119 return size;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2123 WINED3DVERTEXELEMENT* elements = NULL;
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2125 unsigned int size;
2126 DWORD hr;
2128 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2129 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2131 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2132 HeapFree(GetProcessHeap(), 0, elements);
2133 if (hr != S_OK) return hr;
2135 return WINED3D_OK;
2138 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2140 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2141 HRESULT hr = WINED3D_OK;
2143 if (!pFunction) return WINED3DERR_INVALIDCALL;
2145 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2146 if (!object)
2148 ERR("Out of memory\n");
2149 *ppVertexShader = NULL;
2150 return WINED3DERR_OUTOFVIDEOMEMORY;
2153 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2154 object->parent = parent;
2155 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2156 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2157 *ppVertexShader = (IWineD3DVertexShader *)object;
2159 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2161 if (vertex_declaration) {
2162 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2165 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2166 if (FAILED(hr))
2168 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2169 IWineD3DVertexShader_Release(*ppVertexShader);
2170 *ppVertexShader = NULL;
2171 return hr;
2174 return hr;
2177 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2179 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2180 HRESULT hr = WINED3D_OK;
2182 if (!pFunction) return WINED3DERR_INVALIDCALL;
2184 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2185 if (!object)
2187 ERR("Out of memory\n");
2188 *ppPixelShader = NULL;
2189 return WINED3DERR_OUTOFVIDEOMEMORY;
2192 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2193 object->parent = parent;
2194 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2195 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2196 *ppPixelShader = (IWineD3DPixelShader *)object;
2198 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2200 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2201 if (FAILED(hr))
2203 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2204 IWineD3DPixelShader_Release(*ppPixelShader);
2205 *ppPixelShader = NULL;
2206 return hr;
2209 return hr;
2212 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2213 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2216 IWineD3DPaletteImpl *object;
2217 HRESULT hr;
2218 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2220 /* Create the new object */
2221 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2222 if(!object) {
2223 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2224 return E_OUTOFMEMORY;
2227 object->lpVtbl = &IWineD3DPalette_Vtbl;
2228 object->ref = 1;
2229 object->Flags = Flags;
2230 object->parent = Parent;
2231 object->wineD3DDevice = This;
2232 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2233 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2235 if(!object->hpal) {
2236 HeapFree( GetProcessHeap(), 0, object);
2237 return E_OUTOFMEMORY;
2240 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2241 if(FAILED(hr)) {
2242 IWineD3DPalette_Release((IWineD3DPalette *) object);
2243 return hr;
2246 *Palette = (IWineD3DPalette *) object;
2248 return WINED3D_OK;
2251 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2252 HBITMAP hbm;
2253 BITMAP bm;
2254 HRESULT hr;
2255 HDC dcb = NULL, dcs = NULL;
2256 WINEDDCOLORKEY colorkey;
2258 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2259 if(hbm)
2261 GetObjectA(hbm, sizeof(BITMAP), &bm);
2262 dcb = CreateCompatibleDC(NULL);
2263 if(!dcb) goto out;
2264 SelectObject(dcb, hbm);
2266 else
2268 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2269 * couldn't be loaded
2271 memset(&bm, 0, sizeof(bm));
2272 bm.bmWidth = 32;
2273 bm.bmHeight = 32;
2276 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2277 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2278 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2279 if(FAILED(hr)) {
2280 ERR("Wine logo requested, but failed to create surface\n");
2281 goto out;
2284 if(dcb) {
2285 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2286 if(FAILED(hr)) goto out;
2287 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2288 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2290 colorkey.dwColorSpaceLowValue = 0;
2291 colorkey.dwColorSpaceHighValue = 0;
2292 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2293 } else {
2294 /* Fill the surface with a white color to show that wined3d is there */
2295 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2298 out:
2299 if(dcb) {
2300 DeleteDC(dcb);
2302 if(hbm) {
2303 DeleteObject(hbm);
2305 return;
2308 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2309 unsigned int i;
2310 /* Under DirectX you can have texture stage operations even if no texture is
2311 bound, whereas opengl will only do texture operations when a valid texture is
2312 bound. We emulate this by creating dummy textures and binding them to each
2313 texture stage, but disable all stages by default. Hence if a stage is enabled
2314 then the default texture will kick in until replaced by a SetTexture call */
2315 ENTER_GL();
2317 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2318 /* The dummy texture does not have client storage backing */
2319 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2320 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2322 for (i = 0; i < GL_LIMITS(textures); i++) {
2323 GLubyte white = 255;
2325 /* Make appropriate texture active */
2326 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2327 checkGLcall("glActiveTextureARB");
2329 /* Generate an opengl texture name */
2330 glGenTextures(1, &This->dummyTextureName[i]);
2331 checkGLcall("glGenTextures");
2332 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2334 /* Generate a dummy 2d texture (not using 1d because they cause many
2335 * DRI drivers fall back to sw) */
2336 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2337 checkGLcall("glBindTexture");
2339 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2340 checkGLcall("glTexImage2D");
2342 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2343 /* Reenable because if supported it is enabled by default */
2344 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2345 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2348 LEAVE_GL();
2351 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2352 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2355 IWineD3DSwapChainImpl *swapchain = NULL;
2356 HRESULT hr;
2357 DWORD state;
2358 unsigned int i;
2360 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2362 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2363 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2365 /* TODO: Test if OpenGL is compiled in and loaded */
2367 TRACE("(%p) : Creating stateblock\n", This);
2368 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2369 hr = IWineD3DDevice_CreateStateBlock(iface,
2370 WINED3DSBT_INIT,
2371 (IWineD3DStateBlock **)&This->stateBlock,
2372 NULL);
2373 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2374 WARN("Failed to create stateblock\n");
2375 goto err_out;
2377 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2378 This->updateStateBlock = This->stateBlock;
2379 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2381 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2382 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2384 This->NumberOfPalettes = 1;
2385 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2386 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2387 ERR("Out of memory!\n");
2388 goto err_out;
2390 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2391 if(!This->palettes[0]) {
2392 ERR("Out of memory!\n");
2393 goto err_out;
2395 for (i = 0; i < 256; ++i) {
2396 This->palettes[0][i].peRed = 0xFF;
2397 This->palettes[0][i].peGreen = 0xFF;
2398 This->palettes[0][i].peBlue = 0xFF;
2399 This->palettes[0][i].peFlags = 0xFF;
2401 This->currentPalette = 0;
2403 /* Initialize the texture unit mapping to a 1:1 mapping */
2404 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2405 if (state < GL_LIMITS(fragment_samplers)) {
2406 This->texUnitMap[state] = state;
2407 This->rev_tex_unit_map[state] = state;
2408 } else {
2409 This->texUnitMap[state] = -1;
2410 This->rev_tex_unit_map[state] = -1;
2414 /* Setup the implicit swapchain */
2415 TRACE("Creating implicit swapchain\n");
2416 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2417 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2418 if (FAILED(hr))
2420 WARN("Failed to create implicit swapchain\n");
2421 goto err_out;
2424 This->NumberOfSwapChains = 1;
2425 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2426 if(!This->swapchains) {
2427 ERR("Out of memory!\n");
2428 goto err_out;
2430 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2432 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2433 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2434 This->render_targets[0] = swapchain->backBuffer[0];
2435 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2437 else {
2438 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2439 This->render_targets[0] = swapchain->frontBuffer;
2440 This->lastActiveRenderTarget = swapchain->frontBuffer;
2442 IWineD3DSurface_AddRef(This->render_targets[0]);
2443 This->activeContext = swapchain->context[0];
2444 This->lastThread = GetCurrentThreadId();
2446 /* Depth Stencil support */
2447 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2448 if (NULL != This->stencilBufferTarget) {
2449 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2452 hr = This->shader_backend->shader_alloc_private(iface);
2453 if(FAILED(hr)) {
2454 TRACE("Shader private data couldn't be allocated\n");
2455 goto err_out;
2457 hr = This->frag_pipe->alloc_private(iface);
2458 if(FAILED(hr)) {
2459 TRACE("Fragment pipeline private data couldn't be allocated\n");
2460 goto err_out;
2462 hr = This->blitter->alloc_private(iface);
2463 if(FAILED(hr)) {
2464 TRACE("Blitter private data couldn't be allocated\n");
2465 goto err_out;
2468 /* Set up some starting GL setup */
2470 /* Setup all the devices defaults */
2471 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2472 create_dummy_textures(This);
2474 ENTER_GL();
2476 /* Initialize the current view state */
2477 This->view_ident = 1;
2478 This->contexts[0]->last_was_rhw = 0;
2479 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2480 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2482 switch(wined3d_settings.offscreen_rendering_mode) {
2483 case ORM_FBO:
2484 case ORM_PBUFFER:
2485 This->offscreenBuffer = GL_BACK;
2486 break;
2488 case ORM_BACKBUFFER:
2490 if(This->activeContext->aux_buffers > 0) {
2491 TRACE("Using auxilliary buffer for offscreen rendering\n");
2492 This->offscreenBuffer = GL_AUX0;
2493 } else {
2494 TRACE("Using back buffer for offscreen rendering\n");
2495 This->offscreenBuffer = GL_BACK;
2500 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2501 LEAVE_GL();
2503 /* Clear the screen */
2504 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2505 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2506 0x00, 1.0, 0);
2508 This->d3d_initialized = TRUE;
2510 if(wined3d_settings.logo) {
2511 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2513 This->highest_dirty_ps_const = 0;
2514 This->highest_dirty_vs_const = 0;
2515 return WINED3D_OK;
2517 err_out:
2518 HeapFree(GetProcessHeap(), 0, This->render_targets);
2519 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2520 HeapFree(GetProcessHeap(), 0, This->swapchains);
2521 This->NumberOfSwapChains = 0;
2522 if(This->palettes) {
2523 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2524 HeapFree(GetProcessHeap(), 0, This->palettes);
2526 This->NumberOfPalettes = 0;
2527 if(swapchain) {
2528 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2530 if(This->stateBlock) {
2531 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2532 This->stateBlock = NULL;
2534 if (This->blit_priv) {
2535 This->blitter->free_private(iface);
2537 if (This->fragment_priv) {
2538 This->frag_pipe->free_private(iface);
2540 if (This->shader_priv) {
2541 This->shader_backend->shader_free_private(iface);
2543 return hr;
2546 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2547 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2550 IWineD3DSwapChainImpl *swapchain = NULL;
2551 HRESULT hr;
2553 /* Setup the implicit swapchain */
2554 TRACE("Creating implicit swapchain\n");
2555 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2556 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2557 if (FAILED(hr))
2559 WARN("Failed to create implicit swapchain\n");
2560 goto err_out;
2563 This->NumberOfSwapChains = 1;
2564 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2565 if(!This->swapchains) {
2566 ERR("Out of memory!\n");
2567 goto err_out;
2569 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2570 return WINED3D_OK;
2572 err_out:
2573 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2574 return hr;
2577 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2579 int sampler;
2580 UINT i;
2581 TRACE("(%p)\n", This);
2583 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2585 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2586 * it was created. Thus make sure a context is active for the glDelete* calls
2588 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2590 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2592 TRACE("Deleting high order patches\n");
2593 for(i = 0; i < PATCHMAP_SIZE; i++) {
2594 struct list *e1, *e2;
2595 struct WineD3DRectPatch *patch;
2596 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2597 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2598 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2602 /* Delete the palette conversion shader if it is around */
2603 if(This->paletteConversionShader) {
2604 ENTER_GL();
2605 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2606 LEAVE_GL();
2607 This->paletteConversionShader = 0;
2610 /* Delete the pbuffer context if there is any */
2611 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2613 /* Delete the mouse cursor texture */
2614 if(This->cursorTexture) {
2615 ENTER_GL();
2616 glDeleteTextures(1, &This->cursorTexture);
2617 LEAVE_GL();
2618 This->cursorTexture = 0;
2621 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2622 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2624 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2625 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2628 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2629 * private data, it might contain opengl pointers
2631 if(This->depth_blt_texture) {
2632 glDeleteTextures(1, &This->depth_blt_texture);
2633 This->depth_blt_texture = 0;
2635 if (This->depth_blt_rb) {
2636 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2637 This->depth_blt_rb = 0;
2638 This->depth_blt_rb_w = 0;
2639 This->depth_blt_rb_h = 0;
2642 /* Release the update stateblock */
2643 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2644 if(This->updateStateBlock != This->stateBlock)
2645 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2647 This->updateStateBlock = NULL;
2649 { /* because were not doing proper internal refcounts releasing the primary state block
2650 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2651 to set this->stateBlock = NULL; first */
2652 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2653 This->stateBlock = NULL;
2655 /* Release the stateblock */
2656 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2657 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2661 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2662 This->blitter->free_private(iface);
2663 This->frag_pipe->free_private(iface);
2664 This->shader_backend->shader_free_private(iface);
2666 /* Release the buffers (with sanity checks)*/
2667 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2668 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2669 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2670 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2672 This->stencilBufferTarget = NULL;
2674 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2675 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2676 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2678 TRACE("Setting rendertarget to NULL\n");
2679 This->render_targets[0] = NULL;
2681 if (This->auto_depth_stencil_buffer) {
2682 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2683 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2685 This->auto_depth_stencil_buffer = NULL;
2688 for(i=0; i < This->NumberOfSwapChains; i++) {
2689 TRACE("Releasing the implicit swapchain %d\n", i);
2690 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2691 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2695 HeapFree(GetProcessHeap(), 0, This->swapchains);
2696 This->swapchains = NULL;
2697 This->NumberOfSwapChains = 0;
2699 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2700 HeapFree(GetProcessHeap(), 0, This->palettes);
2701 This->palettes = NULL;
2702 This->NumberOfPalettes = 0;
2704 HeapFree(GetProcessHeap(), 0, This->render_targets);
2705 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2706 This->render_targets = NULL;
2707 This->draw_buffers = NULL;
2709 This->d3d_initialized = FALSE;
2710 return WINED3D_OK;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2715 unsigned int i;
2717 for(i=0; i < This->NumberOfSwapChains; i++) {
2718 TRACE("Releasing the implicit swapchain %d\n", i);
2719 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2720 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2724 HeapFree(GetProcessHeap(), 0, This->swapchains);
2725 This->swapchains = NULL;
2726 This->NumberOfSwapChains = 0;
2727 return WINED3D_OK;
2730 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2731 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2732 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2734 * There is no way to deactivate thread safety once it is enabled.
2736 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2739 /*For now just store the flag(needed in case of ddraw) */
2740 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2742 return;
2745 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2746 const WINED3DDISPLAYMODE* pMode) {
2747 DEVMODEW devmode;
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 LONG ret;
2750 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2751 RECT clip_rc;
2753 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2755 /* Resize the screen even without a window:
2756 * The app could have unset it with SetCooperativeLevel, but not called
2757 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2758 * but we don't have any hwnd
2761 memset(&devmode, 0, sizeof(devmode));
2762 devmode.dmSize = sizeof(devmode);
2763 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2764 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2765 devmode.dmPelsWidth = pMode->Width;
2766 devmode.dmPelsHeight = pMode->Height;
2768 devmode.dmDisplayFrequency = pMode->RefreshRate;
2769 if (pMode->RefreshRate != 0) {
2770 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2773 /* Only change the mode if necessary */
2774 if( (This->ddraw_width == pMode->Width) &&
2775 (This->ddraw_height == pMode->Height) &&
2776 (This->ddraw_format == pMode->Format) &&
2777 (pMode->RefreshRate == 0) ) {
2778 return WINED3D_OK;
2781 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2782 if (ret != DISP_CHANGE_SUCCESSFUL) {
2783 if(devmode.dmDisplayFrequency != 0) {
2784 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2785 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2786 devmode.dmDisplayFrequency = 0;
2787 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2789 if(ret != DISP_CHANGE_SUCCESSFUL) {
2790 return WINED3DERR_NOTAVAILABLE;
2794 /* Store the new values */
2795 This->ddraw_width = pMode->Width;
2796 This->ddraw_height = pMode->Height;
2797 This->ddraw_format = pMode->Format;
2799 /* And finally clip mouse to our screen */
2800 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2801 ClipCursor(&clip_rc);
2803 return WINED3D_OK;
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 *ppD3D= This->wineD3D;
2809 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2810 IWineD3D_AddRef(*ppD3D);
2811 return WINED3D_OK;
2814 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2818 (This->adapter->TextureRam/(1024*1024)),
2819 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2820 /* return simulated texture memory left */
2821 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2824 /*****
2825 * Get / Set Stream Source
2826 *****/
2827 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2828 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 IWineD3DBuffer *oldSrc;
2833 if (StreamNumber >= MAX_STREAMS) {
2834 WARN("Stream out of range %d\n", StreamNumber);
2835 return WINED3DERR_INVALIDCALL;
2836 } else if(OffsetInBytes & 0x3) {
2837 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2838 return WINED3DERR_INVALIDCALL;
2841 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2842 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2844 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2846 if(oldSrc == pStreamData &&
2847 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2848 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2849 TRACE("Application is setting the old values over, nothing to do\n");
2850 return WINED3D_OK;
2853 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2854 if (pStreamData) {
2855 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2856 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2859 /* Handle recording of state blocks */
2860 if (This->isRecordingState) {
2861 TRACE("Recording... not performing anything\n");
2862 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2863 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2864 return WINED3D_OK;
2867 if (pStreamData != NULL) {
2868 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2869 IWineD3DBuffer_AddRef(pStreamData);
2871 if (oldSrc != NULL) {
2872 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2873 IWineD3DBuffer_Release(oldSrc);
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2878 return WINED3D_OK;
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2882 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2887 This->stateBlock->streamSource[StreamNumber],
2888 This->stateBlock->streamOffset[StreamNumber],
2889 This->stateBlock->streamStride[StreamNumber]);
2891 if (StreamNumber >= MAX_STREAMS) {
2892 WARN("Stream out of range %d\n", StreamNumber);
2893 return WINED3DERR_INVALIDCALL;
2895 *pStream = This->stateBlock->streamSource[StreamNumber];
2896 *pStride = This->stateBlock->streamStride[StreamNumber];
2897 if (pOffset) {
2898 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2901 if (*pStream != NULL) {
2902 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2910 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2912 /* Verify input at least in d3d9 this is invalid*/
2913 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2914 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2915 return WINED3DERR_INVALIDCALL;
2917 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2918 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2919 return WINED3DERR_INVALIDCALL;
2921 if( Divider == 0 ){
2922 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2923 return WINED3DERR_INVALIDCALL;
2926 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2927 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2929 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2930 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2932 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2933 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2944 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2946 TRACE("(%p) : returning %d\n", This, *Divider);
2948 return WINED3D_OK;
2951 /*****
2952 * Get / Set & Multiply Transform
2953 *****/
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 /* Most of this routine, comments included copied from ddraw tree initially: */
2958 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2960 /* Handle recording of state blocks */
2961 if (This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2963 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2964 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2965 return WINED3D_OK;
2969 * If the new matrix is the same as the current one,
2970 * we cut off any further processing. this seems to be a reasonable
2971 * optimization because as was noticed, some apps (warcraft3 for example)
2972 * tend towards setting the same matrix repeatedly for some reason.
2974 * From here on we assume that the new matrix is different, wherever it matters.
2976 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2977 TRACE("The app is setting the same matrix over again\n");
2978 return WINED3D_OK;
2979 } else {
2980 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2984 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2985 where ViewMat = Camera space, WorldMat = world space.
2987 In OpenGL, camera and world space is combined into GL_MODELVIEW
2988 matrix. The Projection matrix stay projection matrix.
2991 /* Capture the times we can just ignore the change for now */
2992 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2993 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2994 /* Handled by the state manager */
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3004 *pMatrix = This->stateBlock->transforms[State];
3005 return WINED3D_OK;
3008 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3009 const WINED3DMATRIX *mat = NULL;
3010 WINED3DMATRIX temp;
3012 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3013 * below means it will be recorded in a state block change, but it
3014 * works regardless where it is recorded.
3015 * If this is found to be wrong, change to StateBlock.
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3020 if (State <= HIGHEST_TRANSFORMSTATE)
3022 mat = &This->updateStateBlock->transforms[State];
3023 } else {
3024 FIXME("Unhandled transform state!!\n");
3027 multiply_matrix(&temp, mat, pMatrix);
3029 /* Apply change via set transform - will reapply to eg. lights this way */
3030 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3033 /*****
3034 * Get / Set Light
3035 *****/
3036 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3037 you can reference any indexes you want as long as that number max are enabled at any
3038 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3039 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3040 but when recording, just build a chain pretty much of commands to be replayed. */
3042 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3043 float rho;
3044 PLIGHTINFOEL *object = NULL;
3045 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3046 struct list *e;
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3051 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3052 * the gl driver.
3054 if(!pLight) {
3055 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3056 return WINED3DERR_INVALIDCALL;
3059 switch(pLight->Type) {
3060 case WINED3DLIGHT_POINT:
3061 case WINED3DLIGHT_SPOT:
3062 case WINED3DLIGHT_PARALLELPOINT:
3063 case WINED3DLIGHT_GLSPOT:
3064 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3065 * most wanted
3067 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3068 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3069 return WINED3DERR_INVALIDCALL;
3071 break;
3073 case WINED3DLIGHT_DIRECTIONAL:
3074 /* Ignores attenuation */
3075 break;
3077 default:
3078 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3079 return WINED3DERR_INVALIDCALL;
3082 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3083 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3084 if(object->OriginalIndex == Index) break;
3085 object = NULL;
3088 if(!object) {
3089 TRACE("Adding new light\n");
3090 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3091 if(!object) {
3092 ERR("Out of memory error when allocating a light\n");
3093 return E_OUTOFMEMORY;
3095 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3096 object->glIndex = -1;
3097 object->OriginalIndex = Index;
3098 object->changed = TRUE;
3101 /* Initialize the object */
3102 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,
3103 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3104 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3105 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3106 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3107 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3108 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3110 /* Save away the information */
3111 object->OriginalParms = *pLight;
3113 switch (pLight->Type) {
3114 case WINED3DLIGHT_POINT:
3115 /* Position */
3116 object->lightPosn[0] = pLight->Position.x;
3117 object->lightPosn[1] = pLight->Position.y;
3118 object->lightPosn[2] = pLight->Position.z;
3119 object->lightPosn[3] = 1.0f;
3120 object->cutoff = 180.0f;
3121 /* FIXME: Range */
3122 break;
3124 case WINED3DLIGHT_DIRECTIONAL:
3125 /* Direction */
3126 object->lightPosn[0] = -pLight->Direction.x;
3127 object->lightPosn[1] = -pLight->Direction.y;
3128 object->lightPosn[2] = -pLight->Direction.z;
3129 object->lightPosn[3] = 0.0;
3130 object->exponent = 0.0f;
3131 object->cutoff = 180.0f;
3132 break;
3134 case WINED3DLIGHT_SPOT:
3135 /* Position */
3136 object->lightPosn[0] = pLight->Position.x;
3137 object->lightPosn[1] = pLight->Position.y;
3138 object->lightPosn[2] = pLight->Position.z;
3139 object->lightPosn[3] = 1.0;
3141 /* Direction */
3142 object->lightDirn[0] = pLight->Direction.x;
3143 object->lightDirn[1] = pLight->Direction.y;
3144 object->lightDirn[2] = pLight->Direction.z;
3145 object->lightDirn[3] = 1.0;
3148 * opengl-ish and d3d-ish spot lights use too different models for the
3149 * light "intensity" as a function of the angle towards the main light direction,
3150 * so we only can approximate very roughly.
3151 * however spot lights are rather rarely used in games (if ever used at all).
3152 * furthermore if still used, probably nobody pays attention to such details.
3154 if (pLight->Falloff == 0) {
3155 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3156 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3157 * will always be 1.0 for both of them, and we don't have to care for the
3158 * rest of the rather complex calculation
3160 object->exponent = 0;
3161 } else {
3162 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3163 if (rho < 0.0001) rho = 0.0001f;
3164 object->exponent = -0.3/log(cos(rho/2));
3166 if (object->exponent > 128.0) {
3167 object->exponent = 128.0;
3169 object->cutoff = pLight->Phi*90/M_PI;
3171 /* FIXME: Range */
3172 break;
3174 default:
3175 FIXME("Unrecognized light type %d\n", pLight->Type);
3178 /* Update the live definitions if the light is currently assigned a glIndex */
3179 if (object->glIndex != -1 && !This->isRecordingState) {
3180 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3182 return WINED3D_OK;
3185 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3186 PLIGHTINFOEL *lightInfo = NULL;
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3189 struct list *e;
3190 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3192 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3193 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3194 if(lightInfo->OriginalIndex == Index) break;
3195 lightInfo = NULL;
3198 if (lightInfo == NULL) {
3199 TRACE("Light information requested but light not defined\n");
3200 return WINED3DERR_INVALIDCALL;
3203 *pLight = lightInfo->OriginalParms;
3204 return WINED3D_OK;
3207 /*****
3208 * Get / Set Light Enable
3209 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3210 *****/
3211 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3212 PLIGHTINFOEL *lightInfo = NULL;
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3215 struct list *e;
3216 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3218 /* Tests show true = 128...not clear why */
3219 Enable = Enable? 128: 0;
3221 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3222 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3223 if(lightInfo->OriginalIndex == Index) break;
3224 lightInfo = NULL;
3226 TRACE("Found light: %p\n", lightInfo);
3228 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3229 if (lightInfo == NULL) {
3231 TRACE("Light enabled requested but light not defined, so defining one!\n");
3232 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3234 /* Search for it again! Should be fairly quick as near head of list */
3235 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3236 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3237 if(lightInfo->OriginalIndex == Index) break;
3238 lightInfo = NULL;
3240 if (lightInfo == NULL) {
3241 FIXME("Adding default lights has failed dismally\n");
3242 return WINED3DERR_INVALIDCALL;
3246 lightInfo->enabledChanged = TRUE;
3247 if(!Enable) {
3248 if(lightInfo->glIndex != -1) {
3249 if(!This->isRecordingState) {
3250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3253 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3254 lightInfo->glIndex = -1;
3255 } else {
3256 TRACE("Light already disabled, nothing to do\n");
3258 lightInfo->enabled = FALSE;
3259 } else {
3260 lightInfo->enabled = TRUE;
3261 if (lightInfo->glIndex != -1) {
3262 /* nop */
3263 TRACE("Nothing to do as light was enabled\n");
3264 } else {
3265 int i;
3266 /* Find a free gl light */
3267 for(i = 0; i < This->maxConcurrentLights; i++) {
3268 if(This->updateStateBlock->activeLights[i] == NULL) {
3269 This->updateStateBlock->activeLights[i] = lightInfo;
3270 lightInfo->glIndex = i;
3271 break;
3274 if(lightInfo->glIndex == -1) {
3275 /* Our tests show that Windows returns D3D_OK in this situation, even with
3276 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3277 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3278 * as well for those lights.
3280 * TODO: Test how this affects rendering
3282 WARN("Too many concurrently active lights\n");
3283 return WINED3D_OK;
3286 /* i == lightInfo->glIndex */
3287 if(!This->isRecordingState) {
3288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3293 return WINED3D_OK;
3296 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3298 PLIGHTINFOEL *lightInfo = NULL;
3299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 struct list *e;
3301 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3302 TRACE("(%p) : for idx(%d)\n", This, Index);
3304 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3305 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3306 if(lightInfo->OriginalIndex == Index) break;
3307 lightInfo = NULL;
3310 if (lightInfo == NULL) {
3311 TRACE("Light enabled state requested but light not defined\n");
3312 return WINED3DERR_INVALIDCALL;
3314 /* true is 128 according to SetLightEnable */
3315 *pEnable = lightInfo->enabled ? 128 : 0;
3316 return WINED3D_OK;
3319 /*****
3320 * Get / Set Clip Planes
3321 *****/
3322 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3326 /* Validate Index */
3327 if (Index >= GL_LIMITS(clipplanes)) {
3328 TRACE("Application has requested clipplane this device doesn't support\n");
3329 return WINED3DERR_INVALIDCALL;
3332 This->updateStateBlock->changed.clipplane |= 1 << Index;
3334 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3335 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3336 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3337 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3338 TRACE("Application is setting old values over, nothing to do\n");
3339 return WINED3D_OK;
3342 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3343 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3344 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3345 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3347 /* Handle recording of state blocks */
3348 if (This->isRecordingState) {
3349 TRACE("Recording... not performing anything\n");
3350 return WINED3D_OK;
3353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3355 return WINED3D_OK;
3358 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3360 TRACE("(%p) : for idx %d\n", This, Index);
3362 /* Validate Index */
3363 if (Index >= GL_LIMITS(clipplanes)) {
3364 TRACE("Application has requested clipplane this device doesn't support\n");
3365 return WINED3DERR_INVALIDCALL;
3368 pPlane[0] = This->stateBlock->clipplane[Index][0];
3369 pPlane[1] = This->stateBlock->clipplane[Index][1];
3370 pPlane[2] = This->stateBlock->clipplane[Index][2];
3371 pPlane[3] = This->stateBlock->clipplane[Index][3];
3372 return WINED3D_OK;
3375 /*****
3376 * Get / Set Clip Plane Status
3377 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3378 *****/
3379 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 FIXME("(%p) : stub\n", This);
3382 if (NULL == pClipStatus) {
3383 return WINED3DERR_INVALIDCALL;
3385 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3386 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3387 return WINED3D_OK;
3390 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 FIXME("(%p) : stub\n", This);
3393 if (NULL == pClipStatus) {
3394 return WINED3DERR_INVALIDCALL;
3396 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3397 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3398 return WINED3D_OK;
3401 /*****
3402 * Get / Set Material
3403 *****/
3404 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 This->updateStateBlock->changed.material = TRUE;
3408 This->updateStateBlock->material = *pMaterial;
3410 /* Handle recording of state blocks */
3411 if (This->isRecordingState) {
3412 TRACE("Recording... not performing anything\n");
3413 return WINED3D_OK;
3416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3417 return WINED3D_OK;
3420 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 *pMaterial = This->updateStateBlock->material;
3423 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3424 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3425 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3426 pMaterial->Ambient.b, pMaterial->Ambient.a);
3427 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3428 pMaterial->Specular.b, pMaterial->Specular.a);
3429 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3430 pMaterial->Emissive.b, pMaterial->Emissive.a);
3431 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3433 return WINED3D_OK;
3436 /*****
3437 * Get / Set Indices
3438 *****/
3439 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 IWineD3DIndexBuffer *oldIdxs;
3443 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3444 oldIdxs = This->updateStateBlock->pIndexData;
3446 This->updateStateBlock->changed.indices = TRUE;
3447 This->updateStateBlock->pIndexData = pIndexData;
3449 /* Handle recording of state blocks */
3450 if (This->isRecordingState) {
3451 TRACE("Recording... not performing anything\n");
3452 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3453 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3454 return WINED3D_OK;
3457 if(oldIdxs != pIndexData) {
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3459 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3460 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3462 return WINED3D_OK;
3465 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3468 *ppIndexData = This->stateBlock->pIndexData;
3470 /* up ref count on ppindexdata */
3471 if (*ppIndexData) {
3472 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3473 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3474 }else{
3475 TRACE("(%p) No index data set\n", This);
3477 TRACE("Returning %p\n", *ppIndexData);
3479 return WINED3D_OK;
3482 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3483 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3485 TRACE("(%p)->(%d)\n", This, BaseIndex);
3487 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3488 TRACE("Application is setting the old value over, nothing to do\n");
3489 return WINED3D_OK;
3492 This->updateStateBlock->baseVertexIndex = BaseIndex;
3494 if (This->isRecordingState) {
3495 TRACE("Recording... not performing anything\n");
3496 return WINED3D_OK;
3498 /* The base vertex index affects the stream sources */
3499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3500 return WINED3D_OK;
3503 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 TRACE("(%p) : base_index %p\n", This, base_index);
3507 *base_index = This->stateBlock->baseVertexIndex;
3509 TRACE("Returning %u\n", *base_index);
3511 return WINED3D_OK;
3514 /*****
3515 * Get / Set Viewports
3516 *****/
3517 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3520 TRACE("(%p)\n", This);
3521 This->updateStateBlock->changed.viewport = TRUE;
3522 This->updateStateBlock->viewport = *pViewport;
3524 /* Handle recording of state blocks */
3525 if (This->isRecordingState) {
3526 TRACE("Recording... not performing anything\n");
3527 return WINED3D_OK;
3530 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3531 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3534 return WINED3D_OK;
3538 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 TRACE("(%p)\n", This);
3541 *pViewport = This->stateBlock->viewport;
3542 return WINED3D_OK;
3545 /*****
3546 * Get / Set Render States
3547 * TODO: Verify against dx9 definitions
3548 *****/
3549 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3552 DWORD oldValue = This->stateBlock->renderState[State];
3554 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3556 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3557 This->updateStateBlock->renderState[State] = Value;
3559 /* Handle recording of state blocks */
3560 if (This->isRecordingState) {
3561 TRACE("Recording... not performing anything\n");
3562 return WINED3D_OK;
3565 /* Compared here and not before the assignment to allow proper stateblock recording */
3566 if(Value == oldValue) {
3567 TRACE("Application is setting the old value over, nothing to do\n");
3568 } else {
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3572 return WINED3D_OK;
3575 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3578 *pValue = This->stateBlock->renderState[State];
3579 return WINED3D_OK;
3582 /*****
3583 * Get / Set Sampler States
3584 * TODO: Verify against dx9 definitions
3585 *****/
3587 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3589 DWORD oldValue;
3591 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3592 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3594 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3595 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3598 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3599 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3600 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3603 * SetSampler is designed to allow for more than the standard up to 8 textures
3604 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3605 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3607 * http://developer.nvidia.com/object/General_FAQ.html#t6
3609 * There are two new settings for GForce
3610 * the sampler one:
3611 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3612 * and the texture one:
3613 * GL_MAX_TEXTURE_COORDS_ARB.
3614 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3615 ******************/
3617 oldValue = This->stateBlock->samplerState[Sampler][Type];
3618 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3619 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3621 /* Handle recording of state blocks */
3622 if (This->isRecordingState) {
3623 TRACE("Recording... not performing anything\n");
3624 return WINED3D_OK;
3627 if(oldValue == Value) {
3628 TRACE("Application is setting the old value over, nothing to do\n");
3629 return WINED3D_OK;
3632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3634 return WINED3D_OK;
3637 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3641 This, Sampler, debug_d3dsamplerstate(Type), Type);
3643 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3644 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3647 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3648 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3649 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3651 *Value = This->stateBlock->samplerState[Sampler][Type];
3652 TRACE("(%p) : Returning %#x\n", This, *Value);
3654 return WINED3D_OK;
3657 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3660 This->updateStateBlock->changed.scissorRect = TRUE;
3661 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3662 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3663 return WINED3D_OK;
3665 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3667 if(This->isRecordingState) {
3668 TRACE("Recording... not performing anything\n");
3669 return WINED3D_OK;
3672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3674 return WINED3D_OK;
3677 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3680 *pRect = This->updateStateBlock->scissorRect;
3681 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3682 return WINED3D_OK;
3685 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3687 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3689 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3691 This->updateStateBlock->vertexDecl = pDecl;
3692 This->updateStateBlock->changed.vertexDecl = TRUE;
3694 if (This->isRecordingState) {
3695 TRACE("Recording... not performing anything\n");
3696 return WINED3D_OK;
3697 } else if(pDecl == oldDecl) {
3698 /* Checked after the assignment to allow proper stateblock recording */
3699 TRACE("Application is setting the old declaration over, nothing to do\n");
3700 return WINED3D_OK;
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3704 return WINED3D_OK;
3707 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3710 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3712 *ppDecl = This->stateBlock->vertexDecl;
3713 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3714 return WINED3D_OK;
3717 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3721 This->updateStateBlock->vertexShader = pShader;
3722 This->updateStateBlock->changed.vertexShader = TRUE;
3724 if (This->isRecordingState) {
3725 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3726 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3727 TRACE("Recording... not performing anything\n");
3728 return WINED3D_OK;
3729 } else if(oldShader == pShader) {
3730 /* Checked here to allow proper stateblock recording */
3731 TRACE("App is setting the old shader over, nothing to do\n");
3732 return WINED3D_OK;
3735 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3736 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3737 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3741 return WINED3D_OK;
3744 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3747 if (NULL == ppShader) {
3748 return WINED3DERR_INVALIDCALL;
3750 *ppShader = This->stateBlock->vertexShader;
3751 if( NULL != *ppShader)
3752 IWineD3DVertexShader_AddRef(*ppShader);
3754 TRACE("(%p) : returning %p\n", This, *ppShader);
3755 return WINED3D_OK;
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3759 IWineD3DDevice *iface,
3760 UINT start,
3761 CONST BOOL *srcData,
3762 UINT count) {
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 int i, cnt = min(count, MAX_CONST_B - start);
3767 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3768 iface, srcData, start, count);
3770 if (srcData == NULL || cnt < 0)
3771 return WINED3DERR_INVALIDCALL;
3773 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3774 for (i = 0; i < cnt; i++)
3775 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3777 for (i = start; i < cnt + start; ++i) {
3778 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3781 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3783 return WINED3D_OK;
3786 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3787 IWineD3DDevice *iface,
3788 UINT start,
3789 BOOL *dstData,
3790 UINT count) {
3792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3793 int cnt = min(count, MAX_CONST_B - start);
3795 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3796 iface, dstData, start, count);
3798 if (dstData == NULL || cnt < 0)
3799 return WINED3DERR_INVALIDCALL;
3801 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3802 return WINED3D_OK;
3805 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3806 IWineD3DDevice *iface,
3807 UINT start,
3808 CONST int *srcData,
3809 UINT count) {
3811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3812 int i, cnt = min(count, MAX_CONST_I - start);
3814 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3815 iface, srcData, start, count);
3817 if (srcData == NULL || cnt < 0)
3818 return WINED3DERR_INVALIDCALL;
3820 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3821 for (i = 0; i < cnt; i++)
3822 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3823 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3825 for (i = start; i < cnt + start; ++i) {
3826 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3829 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3831 return WINED3D_OK;
3834 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3835 IWineD3DDevice *iface,
3836 UINT start,
3837 int *dstData,
3838 UINT count) {
3840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3841 int cnt = min(count, MAX_CONST_I - start);
3843 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3844 iface, dstData, start, count);
3846 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3847 return WINED3DERR_INVALIDCALL;
3849 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3850 return WINED3D_OK;
3853 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3854 IWineD3DDevice *iface,
3855 UINT start,
3856 CONST float *srcData,
3857 UINT count) {
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3860 UINT i;
3862 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3863 iface, srcData, start, count);
3865 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3866 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3867 return WINED3DERR_INVALIDCALL;
3869 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3870 if(TRACE_ON(d3d)) {
3871 for (i = 0; i < count; i++)
3872 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3873 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3876 if (!This->isRecordingState)
3878 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3882 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3883 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3885 return WINED3D_OK;
3888 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3889 IWineD3DDevice *iface,
3890 UINT start,
3891 float *dstData,
3892 UINT count) {
3894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3895 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3897 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3898 iface, dstData, start, count);
3900 if (dstData == NULL || cnt < 0)
3901 return WINED3DERR_INVALIDCALL;
3903 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3904 return WINED3D_OK;
3907 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3908 DWORD i;
3909 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3915 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3916 int i = This->rev_tex_unit_map[unit];
3917 int j = This->texUnitMap[stage];
3919 This->texUnitMap[stage] = unit;
3920 if (i != -1 && i != stage) {
3921 This->texUnitMap[i] = -1;
3924 This->rev_tex_unit_map[unit] = stage;
3925 if (j != -1 && j != unit) {
3926 This->rev_tex_unit_map[j] = -1;
3930 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3931 int i;
3933 This->fixed_function_usage_map = 0;
3934 for (i = 0; i < MAX_TEXTURES; ++i) {
3935 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3936 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3937 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3938 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3939 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3940 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3941 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3942 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3944 if (color_op == WINED3DTOP_DISABLE) {
3945 /* Not used, and disable higher stages */
3946 break;
3949 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3950 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3951 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3952 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3953 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3954 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3955 This->fixed_function_usage_map |= (1 << i);
3958 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3959 This->fixed_function_usage_map |= (1 << (i + 1));
3964 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3965 int i, tex;
3966 WORD ffu_map;
3968 device_update_fixed_function_usage_map(This);
3969 ffu_map = This->fixed_function_usage_map;
3971 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3972 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3973 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3975 if (!(ffu_map & 1)) continue;
3977 if (This->texUnitMap[i] != i) {
3978 device_map_stage(This, i, i);
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3980 markTextureStagesDirty(This, i);
3983 return;
3986 /* Now work out the mapping */
3987 tex = 0;
3988 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3990 if (!(ffu_map & 1)) continue;
3992 if (This->texUnitMap[i] != tex) {
3993 device_map_stage(This, i, tex);
3994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3995 markTextureStagesDirty(This, i);
3998 ++tex;
4002 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4003 const DWORD *sampler_tokens =
4004 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4005 int i;
4007 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4008 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4009 device_map_stage(This, i, i);
4010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4011 if (i < MAX_TEXTURES) {
4012 markTextureStagesDirty(This, i);
4018 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4019 const DWORD *vshader_sampler_tokens, int unit)
4021 int current_mapping = This->rev_tex_unit_map[unit];
4023 if (current_mapping == -1) {
4024 /* Not currently used */
4025 return TRUE;
4028 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4029 /* Used by a fragment sampler */
4031 if (!pshader_sampler_tokens) {
4032 /* No pixel shader, check fixed function */
4033 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4036 /* Pixel shader, check the shader's sampler map */
4037 return !pshader_sampler_tokens[current_mapping];
4040 /* Used by a vertex sampler */
4041 return !vshader_sampler_tokens[current_mapping];
4044 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4045 const DWORD *vshader_sampler_tokens =
4046 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4047 const DWORD *pshader_sampler_tokens = NULL;
4048 int start = GL_LIMITS(combined_samplers) - 1;
4049 int i;
4051 if (ps) {
4052 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4054 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4055 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4056 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4059 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4060 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4061 if (vshader_sampler_tokens[i]) {
4062 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4064 /* Already mapped somewhere */
4065 continue;
4068 while (start >= 0) {
4069 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4070 device_map_stage(This, vsampler_idx, start);
4071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4073 --start;
4074 break;
4077 --start;
4083 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4084 BOOL vs = use_vs(This->stateBlock);
4085 BOOL ps = use_ps(This->stateBlock);
4087 * Rules are:
4088 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4089 * that would be really messy and require shader recompilation
4090 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4091 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4093 if (ps) {
4094 device_map_psamplers(This);
4095 } else {
4096 device_map_fixed_function_samplers(This);
4099 if (vs) {
4100 device_map_vsamplers(This, ps);
4104 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4107 This->updateStateBlock->pixelShader = pShader;
4108 This->updateStateBlock->changed.pixelShader = TRUE;
4110 /* Handle recording of state blocks */
4111 if (This->isRecordingState) {
4112 TRACE("Recording... not performing anything\n");
4115 if (This->isRecordingState) {
4116 TRACE("Recording... not performing anything\n");
4117 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4118 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4119 return WINED3D_OK;
4122 if(pShader == oldShader) {
4123 TRACE("App is setting the old pixel shader over, nothing to do\n");
4124 return WINED3D_OK;
4127 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4128 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4130 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4133 return WINED3D_OK;
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 if (NULL == ppShader) {
4140 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4141 return WINED3DERR_INVALIDCALL;
4144 *ppShader = This->stateBlock->pixelShader;
4145 if (NULL != *ppShader) {
4146 IWineD3DPixelShader_AddRef(*ppShader);
4148 TRACE("(%p) : returning %p\n", This, *ppShader);
4149 return WINED3D_OK;
4152 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4153 IWineD3DDevice *iface,
4154 UINT start,
4155 CONST BOOL *srcData,
4156 UINT count) {
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 int i, cnt = min(count, MAX_CONST_B - start);
4161 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4162 iface, srcData, start, count);
4164 if (srcData == NULL || cnt < 0)
4165 return WINED3DERR_INVALIDCALL;
4167 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4168 for (i = 0; i < cnt; i++)
4169 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4171 for (i = start; i < cnt + start; ++i) {
4172 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4175 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4177 return WINED3D_OK;
4180 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4181 IWineD3DDevice *iface,
4182 UINT start,
4183 BOOL *dstData,
4184 UINT count) {
4186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4187 int cnt = min(count, MAX_CONST_B - start);
4189 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4190 iface, dstData, start, count);
4192 if (dstData == NULL || cnt < 0)
4193 return WINED3DERR_INVALIDCALL;
4195 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4196 return WINED3D_OK;
4199 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4200 IWineD3DDevice *iface,
4201 UINT start,
4202 CONST int *srcData,
4203 UINT count) {
4205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4206 int i, cnt = min(count, MAX_CONST_I - start);
4208 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4209 iface, srcData, start, count);
4211 if (srcData == NULL || cnt < 0)
4212 return WINED3DERR_INVALIDCALL;
4214 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4215 for (i = 0; i < cnt; i++)
4216 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4217 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4219 for (i = start; i < cnt + start; ++i) {
4220 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4223 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4225 return WINED3D_OK;
4228 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4229 IWineD3DDevice *iface,
4230 UINT start,
4231 int *dstData,
4232 UINT count) {
4234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4235 int cnt = min(count, MAX_CONST_I - start);
4237 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4238 iface, dstData, start, count);
4240 if (dstData == NULL || cnt < 0)
4241 return WINED3DERR_INVALIDCALL;
4243 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4244 return WINED3D_OK;
4247 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4248 IWineD3DDevice *iface,
4249 UINT start,
4250 CONST float *srcData,
4251 UINT count) {
4253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4254 UINT i;
4256 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4257 iface, srcData, start, count);
4259 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4260 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4261 return WINED3DERR_INVALIDCALL;
4263 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4264 if(TRACE_ON(d3d)) {
4265 for (i = 0; i < count; i++)
4266 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4267 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4270 if (!This->isRecordingState)
4272 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4276 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4277 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4279 return WINED3D_OK;
4282 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4283 IWineD3DDevice *iface,
4284 UINT start,
4285 float *dstData,
4286 UINT count) {
4288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4289 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4291 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4292 iface, dstData, start, count);
4294 if (dstData == NULL || cnt < 0)
4295 return WINED3DERR_INVALIDCALL;
4297 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4298 return WINED3D_OK;
4301 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4302 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4303 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4305 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4306 unsigned int i;
4307 DWORD DestFVF = dest->fvf;
4308 WINED3DVIEWPORT vp;
4309 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4310 BOOL doClip;
4311 DWORD numTextures;
4313 if (lpStrideData->u.s.normal.lpData) {
4314 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4317 if (lpStrideData->u.s.position.lpData == NULL) {
4318 ERR("Source has no position mask\n");
4319 return WINED3DERR_INVALIDCALL;
4322 /* We might access VBOs from this code, so hold the lock */
4323 ENTER_GL();
4325 if (dest->resource.allocatedMemory == NULL) {
4326 /* This may happen if we do direct locking into a vbo. Unlikely,
4327 * but theoretically possible(ddraw processvertices test)
4329 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4330 if(!dest->resource.allocatedMemory) {
4331 LEAVE_GL();
4332 ERR("Out of memory\n");
4333 return E_OUTOFMEMORY;
4335 if (dest->buffer_object)
4337 const void *src;
4338 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4339 checkGLcall("glBindBufferARB");
4340 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4341 if(src) {
4342 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4344 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4345 checkGLcall("glUnmapBufferARB");
4349 /* Get a pointer into the destination vbo(create one if none exists) and
4350 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4352 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4354 dest->flags |= WINED3D_BUFFER_CREATEBO;
4355 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4358 if (dest->buffer_object)
4360 unsigned char extrabytes = 0;
4361 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4362 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4363 * this may write 4 extra bytes beyond the area that should be written
4365 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4366 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4367 if(!dest_conv_addr) {
4368 ERR("Out of memory\n");
4369 /* Continue without storing converted vertices */
4371 dest_conv = dest_conv_addr;
4374 /* Should I clip?
4375 * a) WINED3DRS_CLIPPING is enabled
4376 * b) WINED3DVOP_CLIP is passed
4378 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4379 static BOOL warned = FALSE;
4381 * The clipping code is not quite correct. Some things need
4382 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4383 * so disable clipping for now.
4384 * (The graphics in Half-Life are broken, and my processvertices
4385 * test crashes with IDirect3DDevice3)
4386 doClip = TRUE;
4388 doClip = FALSE;
4389 if(!warned) {
4390 warned = TRUE;
4391 FIXME("Clipping is broken and disabled for now\n");
4393 } else doClip = FALSE;
4394 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4396 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4397 WINED3DTS_VIEW,
4398 &view_mat);
4399 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4400 WINED3DTS_PROJECTION,
4401 &proj_mat);
4402 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4403 WINED3DTS_WORLDMATRIX(0),
4404 &world_mat);
4406 TRACE("View mat:\n");
4407 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);
4408 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);
4409 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);
4410 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);
4412 TRACE("Proj mat:\n");
4413 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);
4414 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);
4415 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);
4416 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);
4418 TRACE("World mat:\n");
4419 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);
4420 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);
4421 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);
4422 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);
4424 /* Get the viewport */
4425 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4426 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4427 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4429 multiply_matrix(&mat,&view_mat,&world_mat);
4430 multiply_matrix(&mat,&proj_mat,&mat);
4432 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4434 for (i = 0; i < dwCount; i+= 1) {
4435 unsigned int tex_index;
4437 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4438 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4439 /* The position first */
4440 const float *p =
4441 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4442 float x, y, z, rhw;
4443 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4445 /* Multiplication with world, view and projection matrix */
4446 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);
4447 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);
4448 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);
4449 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);
4451 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4453 /* WARNING: The following things are taken from d3d7 and were not yet checked
4454 * against d3d8 or d3d9!
4457 /* Clipping conditions: From msdn
4459 * A vertex is clipped if it does not match the following requirements
4460 * -rhw < x <= rhw
4461 * -rhw < y <= rhw
4462 * 0 < z <= rhw
4463 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4465 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4466 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4470 if( !doClip ||
4471 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4472 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4473 ( rhw > eps ) ) ) {
4475 /* "Normal" viewport transformation (not clipped)
4476 * 1) The values are divided by rhw
4477 * 2) The y axis is negative, so multiply it with -1
4478 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4479 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4480 * 4) Multiply x with Width/2 and add Width/2
4481 * 5) The same for the height
4482 * 6) Add the viewpoint X and Y to the 2D coordinates and
4483 * The minimum Z value to z
4484 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4486 * Well, basically it's simply a linear transformation into viewport
4487 * coordinates
4490 x /= rhw;
4491 y /= rhw;
4492 z /= rhw;
4494 y *= -1;
4496 x *= vp.Width / 2;
4497 y *= vp.Height / 2;
4498 z *= vp.MaxZ - vp.MinZ;
4500 x += vp.Width / 2 + vp.X;
4501 y += vp.Height / 2 + vp.Y;
4502 z += vp.MinZ;
4504 rhw = 1 / rhw;
4505 } else {
4506 /* That vertex got clipped
4507 * Contrary to OpenGL it is not dropped completely, it just
4508 * undergoes a different calculation.
4510 TRACE("Vertex got clipped\n");
4511 x += rhw;
4512 y += rhw;
4514 x /= 2;
4515 y /= 2;
4517 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4518 * outside of the main vertex buffer memory. That needs some more
4519 * investigation...
4523 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4526 ( (float *) dest_ptr)[0] = x;
4527 ( (float *) dest_ptr)[1] = y;
4528 ( (float *) dest_ptr)[2] = z;
4529 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4531 dest_ptr += 3 * sizeof(float);
4533 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4534 dest_ptr += sizeof(float);
4537 if(dest_conv) {
4538 float w = 1 / rhw;
4539 ( (float *) dest_conv)[0] = x * w;
4540 ( (float *) dest_conv)[1] = y * w;
4541 ( (float *) dest_conv)[2] = z * w;
4542 ( (float *) dest_conv)[3] = w;
4544 dest_conv += 3 * sizeof(float);
4546 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4547 dest_conv += sizeof(float);
4551 if (DestFVF & WINED3DFVF_PSIZE) {
4552 dest_ptr += sizeof(DWORD);
4553 if(dest_conv) dest_conv += sizeof(DWORD);
4555 if (DestFVF & WINED3DFVF_NORMAL) {
4556 const float *normal =
4557 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4558 /* AFAIK this should go into the lighting information */
4559 FIXME("Didn't expect the destination to have a normal\n");
4560 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4561 if(dest_conv) {
4562 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4566 if (DestFVF & WINED3DFVF_DIFFUSE) {
4567 const DWORD *color_d =
4568 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4569 if(!color_d) {
4570 static BOOL warned = FALSE;
4572 if(!warned) {
4573 ERR("No diffuse color in source, but destination has one\n");
4574 warned = TRUE;
4577 *( (DWORD *) dest_ptr) = 0xffffffff;
4578 dest_ptr += sizeof(DWORD);
4580 if(dest_conv) {
4581 *( (DWORD *) dest_conv) = 0xffffffff;
4582 dest_conv += sizeof(DWORD);
4585 else {
4586 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4587 if(dest_conv) {
4588 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4589 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4590 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4591 dest_conv += sizeof(DWORD);
4596 if (DestFVF & WINED3DFVF_SPECULAR) {
4597 /* What's the color value in the feedback buffer? */
4598 const DWORD *color_s =
4599 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4600 if(!color_s) {
4601 static BOOL warned = FALSE;
4603 if(!warned) {
4604 ERR("No specular color in source, but destination has one\n");
4605 warned = TRUE;
4608 *( (DWORD *) dest_ptr) = 0xFF000000;
4609 dest_ptr += sizeof(DWORD);
4611 if(dest_conv) {
4612 *( (DWORD *) dest_conv) = 0xFF000000;
4613 dest_conv += sizeof(DWORD);
4616 else {
4617 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4618 if(dest_conv) {
4619 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4620 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4621 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4622 dest_conv += sizeof(DWORD);
4627 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4628 const float *tex_coord =
4629 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4630 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4631 if(!tex_coord) {
4632 ERR("No source texture, but destination requests one\n");
4633 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4634 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4636 else {
4637 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4638 if(dest_conv) {
4639 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4645 if(dest_conv) {
4646 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4647 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4648 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4649 dwCount * get_flexible_vertex_size(DestFVF),
4650 dest_conv_addr));
4651 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4652 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4655 LEAVE_GL();
4657 return WINED3D_OK;
4659 #undef copy_and_next
4661 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4662 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665 WineDirect3DVertexStridedData strided;
4666 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4667 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4669 if(pVertexDecl) {
4670 ERR("Output vertex declaration not implemented yet\n");
4673 /* Need any context to write to the vbo. */
4674 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4676 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4677 * control the streamIsUP flag, thus restore it afterwards.
4679 This->stateBlock->streamIsUP = FALSE;
4680 memset(&strided, 0, sizeof(strided));
4681 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4682 This->stateBlock->streamIsUP = streamWasUP;
4684 if(vbo || SrcStartIndex) {
4685 unsigned int i;
4686 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4687 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4689 * Also get the start index in, but only loop over all elements if there's something to add at all.
4691 #define FIXSRC(type) \
4692 if(strided.u.s.type.VBO) { \
4693 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4694 strided.u.s.type.VBO = 0; \
4695 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4696 ENTER_GL(); \
4697 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4698 vb->buffer_object = 0; \
4699 LEAVE_GL(); \
4701 if(strided.u.s.type.lpData) { \
4702 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4704 FIXSRC(position);
4705 FIXSRC(blendWeights);
4706 FIXSRC(blendMatrixIndices);
4707 FIXSRC(normal);
4708 FIXSRC(pSize);
4709 FIXSRC(diffuse);
4710 FIXSRC(specular);
4711 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4712 FIXSRC(texCoords[i]);
4714 FIXSRC(position2);
4715 FIXSRC(normal2);
4716 FIXSRC(tangent);
4717 FIXSRC(binormal);
4718 FIXSRC(tessFactor);
4719 FIXSRC(fog);
4720 FIXSRC(depth);
4721 FIXSRC(sample);
4722 #undef FIXSRC
4725 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4726 (struct wined3d_buffer *)pDestBuffer, Flags);
4729 /*****
4730 * Get / Set Texture Stage States
4731 * TODO: Verify against dx9 definitions
4732 *****/
4733 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4735 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4737 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4739 if (Stage >= MAX_TEXTURES) {
4740 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4741 return WINED3D_OK;
4744 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4745 This->updateStateBlock->textureState[Stage][Type] = Value;
4747 if (This->isRecordingState) {
4748 TRACE("Recording... not performing anything\n");
4749 return WINED3D_OK;
4752 /* Checked after the assignments to allow proper stateblock recording */
4753 if(oldValue == Value) {
4754 TRACE("App is setting the old value over, nothing to do\n");
4755 return WINED3D_OK;
4758 if(Stage > This->stateBlock->lowest_disabled_stage &&
4759 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4760 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4761 * Changes in other states are important on disabled stages too
4763 return WINED3D_OK;
4766 if(Type == WINED3DTSS_COLOROP) {
4767 int i;
4769 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4770 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4771 * they have to be disabled
4773 * The current stage is dirtified below.
4775 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4776 TRACE("Additionally dirtifying stage %d\n", i);
4777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4779 This->stateBlock->lowest_disabled_stage = Stage;
4780 TRACE("New lowest disabled: %d\n", Stage);
4781 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4782 /* Previously disabled stage enabled. Stages above it may need enabling
4783 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4784 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4786 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4789 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4790 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4791 break;
4793 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4796 This->stateBlock->lowest_disabled_stage = i;
4797 TRACE("New lowest disabled: %d\n", i);
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4803 return WINED3D_OK;
4806 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4809 *pValue = This->updateStateBlock->textureState[Stage][Type];
4810 return WINED3D_OK;
4813 /*****
4814 * Get / Set Texture
4815 *****/
4816 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 IWineD3DBaseTexture *oldTexture;
4820 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4822 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4823 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4826 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4827 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4828 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4831 oldTexture = This->updateStateBlock->textures[Stage];
4833 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4834 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4836 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4837 return WINED3DERR_INVALIDCALL;
4840 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4841 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4843 This->updateStateBlock->changed.textures |= 1 << Stage;
4844 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4845 This->updateStateBlock->textures[Stage] = pTexture;
4847 /* Handle recording of state blocks */
4848 if (This->isRecordingState) {
4849 TRACE("Recording... not performing anything\n");
4850 return WINED3D_OK;
4853 if(oldTexture == pTexture) {
4854 TRACE("App is setting the same texture again, nothing to do\n");
4855 return WINED3D_OK;
4858 /** NOTE: MSDN says that setTexture increases the reference count,
4859 * and that the application must set the texture back to null (or have a leaky application),
4860 * This means we should pass the refcount up to the parent
4861 *******************************/
4862 if (NULL != This->updateStateBlock->textures[Stage]) {
4863 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4864 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4865 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4867 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4869 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4874 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4875 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4876 * so the COLOROP and ALPHAOP have to be dirtified.
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4881 if(bindCount == 1) {
4882 new->baseTexture.sampler = Stage;
4884 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4888 if (NULL != oldTexture) {
4889 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4890 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4892 IWineD3DBaseTexture_Release(oldTexture);
4893 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4898 if(bindCount && old->baseTexture.sampler == Stage) {
4899 int i;
4900 /* Have to do a search for the other sampler(s) where the texture is bound to
4901 * Shouldn't happen as long as apps bind a texture only to one stage
4903 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4904 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4905 if(This->updateStateBlock->textures[i] == oldTexture) {
4906 old->baseTexture.sampler = i;
4907 break;
4913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4915 return WINED3D_OK;
4918 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4921 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4923 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4924 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4927 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4928 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4929 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4932 *ppTexture=This->stateBlock->textures[Stage];
4933 if (*ppTexture)
4934 IWineD3DBaseTexture_AddRef(*ppTexture);
4936 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4938 return WINED3D_OK;
4941 /*****
4942 * Get Back Buffer
4943 *****/
4944 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4945 IWineD3DSurface **ppBackBuffer) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 IWineD3DSwapChain *swapChain;
4948 HRESULT hr;
4950 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4952 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4953 if (hr == WINED3D_OK) {
4954 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4955 IWineD3DSwapChain_Release(swapChain);
4956 } else {
4957 *ppBackBuffer = NULL;
4959 return hr;
4962 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4964 WARN("(%p) : stub, calling idirect3d for now\n", This);
4965 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4968 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 IWineD3DSwapChain *swapChain;
4971 HRESULT hr;
4973 if(iSwapChain > 0) {
4974 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4975 if (hr == WINED3D_OK) {
4976 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4977 IWineD3DSwapChain_Release(swapChain);
4978 } else {
4979 FIXME("(%p) Error getting display mode\n", This);
4981 } else {
4982 /* Don't read the real display mode,
4983 but return the stored mode instead. X11 can't change the color
4984 depth, and some apps are pretty angry if they SetDisplayMode from
4985 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4987 Also don't relay to the swapchain because with ddraw it's possible
4988 that there isn't a swapchain at all */
4989 pMode->Width = This->ddraw_width;
4990 pMode->Height = This->ddraw_height;
4991 pMode->Format = This->ddraw_format;
4992 pMode->RefreshRate = 0;
4993 hr = WINED3D_OK;
4996 return hr;
4999 /*****
5000 * Stateblock related functions
5001 *****/
5003 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5005 IWineD3DStateBlock *stateblock;
5006 HRESULT hr;
5008 TRACE("(%p)\n", This);
5010 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5012 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5013 if (FAILED(hr)) return hr;
5015 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5016 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5017 This->isRecordingState = TRUE;
5019 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5021 return WINED3D_OK;
5024 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5026 unsigned int i, j;
5027 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5029 if (!This->isRecordingState) {
5030 WARN("(%p) not recording! returning error\n", This);
5031 *ppStateBlock = NULL;
5032 return WINED3DERR_INVALIDCALL;
5035 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5037 DWORD map = object->changed.renderState[i];
5038 for (j = 0; map; map >>= 1, ++j)
5040 if (!(map & 1)) continue;
5042 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5046 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5048 DWORD map = object->changed.transform[i];
5049 for (j = 0; map; map >>= 1, ++j)
5051 if (!(map & 1)) continue;
5053 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5056 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5057 if(object->changed.vertexShaderConstantsF[i]) {
5058 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5059 object->num_contained_vs_consts_f++;
5062 for(i = 0; i < MAX_CONST_I; i++) {
5063 if (object->changed.vertexShaderConstantsI & (1 << i))
5065 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5066 object->num_contained_vs_consts_i++;
5069 for(i = 0; i < MAX_CONST_B; i++) {
5070 if (object->changed.vertexShaderConstantsB & (1 << i))
5072 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5073 object->num_contained_vs_consts_b++;
5076 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5078 if (object->changed.pixelShaderConstantsF[i])
5080 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5081 ++object->num_contained_ps_consts_f;
5084 for(i = 0; i < MAX_CONST_I; i++) {
5085 if (object->changed.pixelShaderConstantsI & (1 << i))
5087 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5088 object->num_contained_ps_consts_i++;
5091 for(i = 0; i < MAX_CONST_B; i++) {
5092 if (object->changed.pixelShaderConstantsB & (1 << i))
5094 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5095 object->num_contained_ps_consts_b++;
5098 for(i = 0; i < MAX_TEXTURES; i++) {
5099 DWORD map = object->changed.textureState[i];
5101 for(j = 0; map; map >>= 1, ++j)
5103 if (!(map & 1)) continue;
5105 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5106 object->contained_tss_states[object->num_contained_tss_states].state = j;
5107 ++object->num_contained_tss_states;
5110 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5111 DWORD map = object->changed.samplerState[i];
5113 for (j = 0; map; map >>= 1, ++j)
5115 if (!(map & 1)) continue;
5117 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5118 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5119 ++object->num_contained_sampler_states;
5123 *ppStateBlock = (IWineD3DStateBlock*) object;
5124 This->isRecordingState = FALSE;
5125 This->updateStateBlock = This->stateBlock;
5126 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5127 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5128 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5129 return WINED3D_OK;
5132 /*****
5133 * Scene related functions
5134 *****/
5135 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5136 /* At the moment we have no need for any functionality at the beginning
5137 of a scene */
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5139 TRACE("(%p)\n", This);
5141 if(This->inScene) {
5142 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5143 return WINED3DERR_INVALIDCALL;
5145 This->inScene = TRUE;
5146 return WINED3D_OK;
5149 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 TRACE("(%p)\n", This);
5153 if(!This->inScene) {
5154 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5155 return WINED3DERR_INVALIDCALL;
5158 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5159 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5160 glFlush();
5161 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5162 * fails
5165 This->inScene = FALSE;
5166 return WINED3D_OK;
5169 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5170 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5171 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5173 IWineD3DSwapChain *swapChain = NULL;
5174 int i;
5175 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5177 TRACE("(%p) Presenting the frame\n", This);
5179 for(i = 0 ; i < swapchains ; i ++) {
5181 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5182 TRACE("presentinng chain %d, %p\n", i, swapChain);
5183 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5184 IWineD3DSwapChain_Release(swapChain);
5187 return WINED3D_OK;
5190 /* Not called from the VTable (internal subroutine) */
5191 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5192 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5193 float Z, DWORD Stencil) {
5194 GLbitfield glMask = 0;
5195 unsigned int i;
5196 WINED3DRECT curRect;
5197 RECT vp_rect;
5198 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5199 UINT drawable_width, drawable_height;
5200 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5201 IWineD3DSwapChainImpl *swapchain = NULL;
5203 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5204 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5205 * for the cleared parts, and the untouched parts.
5207 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5208 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5209 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5210 * checking all this if the dest surface is in the drawable anyway.
5212 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5213 while(1) {
5214 if(vp->X != 0 || vp->Y != 0 ||
5215 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5216 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5217 break;
5219 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5220 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5221 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5222 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5223 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5224 break;
5226 if(Count > 0 && pRects && (
5227 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5228 pRects[0].x2 < target->currentDesc.Width ||
5229 pRects[0].y2 < target->currentDesc.Height)) {
5230 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5231 break;
5233 break;
5237 target->get_drawable_size(target, &drawable_width, &drawable_height);
5239 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5240 ENTER_GL();
5242 /* Only set the values up once, as they are not changing */
5243 if (Flags & WINED3DCLEAR_STENCIL) {
5244 glClearStencil(Stencil);
5245 checkGLcall("glClearStencil");
5246 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5247 glStencilMask(0xFFFFFFFF);
5250 if (Flags & WINED3DCLEAR_ZBUFFER) {
5251 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5252 glDepthMask(GL_TRUE);
5253 glClearDepth(Z);
5254 checkGLcall("glClearDepth");
5255 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5258 if (vp->X != 0 || vp->Y != 0 ||
5259 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5260 surface_load_ds_location(This->stencilBufferTarget, location);
5262 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5263 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5264 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5265 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5266 surface_load_ds_location(This->stencilBufferTarget, location);
5268 else if (Count > 0 && pRects && (
5269 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5270 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5271 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5272 surface_load_ds_location(This->stencilBufferTarget, location);
5276 if (Flags & WINED3DCLEAR_TARGET) {
5277 TRACE("Clearing screen with glClear to color %x\n", Color);
5278 glClearColor(D3DCOLOR_R(Color),
5279 D3DCOLOR_G(Color),
5280 D3DCOLOR_B(Color),
5281 D3DCOLOR_A(Color));
5282 checkGLcall("glClearColor");
5284 /* Clear ALL colors! */
5285 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5286 glMask = glMask | GL_COLOR_BUFFER_BIT;
5289 vp_rect.left = vp->X;
5290 vp_rect.top = vp->Y;
5291 vp_rect.right = vp->X + vp->Width;
5292 vp_rect.bottom = vp->Y + vp->Height;
5293 if (!(Count > 0 && pRects)) {
5294 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5295 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5297 if(This->render_offscreen) {
5298 glScissor(vp_rect.left, vp_rect.top,
5299 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5300 } else {
5301 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5302 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5304 checkGLcall("glScissor");
5305 glClear(glMask);
5306 checkGLcall("glClear");
5307 } else {
5308 /* Now process each rect in turn */
5309 for (i = 0; i < Count; i++) {
5310 /* Note gl uses lower left, width/height */
5311 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5312 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5313 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5315 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5316 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5317 curRect.x1, (target->currentDesc.Height - curRect.y2),
5318 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5320 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5321 * The rectangle is not cleared, no error is returned, but further rectanlges are
5322 * still cleared if they are valid
5324 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5325 TRACE("Rectangle with negative dimensions, ignoring\n");
5326 continue;
5329 if(This->render_offscreen) {
5330 glScissor(curRect.x1, curRect.y1,
5331 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5332 } else {
5333 glScissor(curRect.x1, drawable_height - curRect.y2,
5334 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5336 checkGLcall("glScissor");
5338 glClear(glMask);
5339 checkGLcall("glClear");
5343 /* Restore the old values (why..?) */
5344 if (Flags & WINED3DCLEAR_STENCIL) {
5345 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5347 if (Flags & WINED3DCLEAR_TARGET) {
5348 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5349 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5350 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5351 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5352 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5354 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5355 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5357 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5359 if (Flags & WINED3DCLEAR_ZBUFFER) {
5360 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5361 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5362 surface_modify_ds_location(This->stencilBufferTarget, location);
5365 LEAVE_GL();
5367 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5368 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5369 glFlush();
5371 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5374 return WINED3D_OK;
5377 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5378 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5380 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5382 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5383 Count, pRects, Flags, Color, Z, Stencil);
5385 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5386 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5387 /* TODO: What about depth stencil buffers without stencil bits? */
5388 return WINED3DERR_INVALIDCALL;
5391 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5394 /*****
5395 * Drawing functions
5396 *****/
5398 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5399 WINED3DPRIMITIVETYPE primitive_type)
5401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5403 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5405 This->updateStateBlock->changed.primitive_type = TRUE;
5406 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5409 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5410 WINED3DPRIMITIVETYPE *primitive_type)
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5416 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5418 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5421 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5425 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5427 if(!This->stateBlock->vertexDecl) {
5428 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5429 return WINED3DERR_INVALIDCALL;
5432 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5433 if(This->stateBlock->streamIsUP) {
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5435 This->stateBlock->streamIsUP = FALSE;
5438 if(This->stateBlock->loadBaseVertexIndex != 0) {
5439 This->stateBlock->loadBaseVertexIndex = 0;
5440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5442 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5443 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5444 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5445 return WINED3D_OK;
5448 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5449 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5452 UINT idxStride = 2;
5453 IWineD3DIndexBuffer *pIB;
5454 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5455 GLuint vbo;
5457 pIB = This->stateBlock->pIndexData;
5458 if (!pIB) {
5459 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5460 * without an index buffer set. (The first time at least...)
5461 * D3D8 simply dies, but I doubt it can do much harm to return
5462 * D3DERR_INVALIDCALL there as well. */
5463 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5464 return WINED3DERR_INVALIDCALL;
5467 if(!This->stateBlock->vertexDecl) {
5468 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5469 return WINED3DERR_INVALIDCALL;
5472 if(This->stateBlock->streamIsUP) {
5473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5474 This->stateBlock->streamIsUP = FALSE;
5476 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5478 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5479 This, minIndex, NumVertices, startIndex, index_count);
5481 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5482 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5483 idxStride = 2;
5484 } else {
5485 idxStride = 4;
5488 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5489 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5493 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5494 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5496 return WINED3D_OK;
5499 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5500 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5503 IWineD3DBuffer *vb;
5505 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5506 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5508 if(!This->stateBlock->vertexDecl) {
5509 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5510 return WINED3DERR_INVALIDCALL;
5513 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5514 vb = This->stateBlock->streamSource[0];
5515 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5516 if (vb) IWineD3DBuffer_Release(vb);
5517 This->stateBlock->streamOffset[0] = 0;
5518 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5519 This->stateBlock->streamIsUP = TRUE;
5520 This->stateBlock->loadBaseVertexIndex = 0;
5522 /* TODO: Only mark dirty if drawing from a different UP address */
5523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5525 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5526 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5528 /* MSDN specifies stream zero settings must be set to NULL */
5529 This->stateBlock->streamStride[0] = 0;
5530 This->stateBlock->streamSource[0] = NULL;
5532 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5533 * the new stream sources or use UP drawing again
5535 return WINED3D_OK;
5538 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5539 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5540 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5542 int idxStride;
5543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5544 IWineD3DBuffer *vb;
5545 IWineD3DIndexBuffer *ib;
5547 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5548 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5549 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5551 if(!This->stateBlock->vertexDecl) {
5552 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5553 return WINED3DERR_INVALIDCALL;
5556 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5557 idxStride = 2;
5558 } else {
5559 idxStride = 4;
5562 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5563 vb = This->stateBlock->streamSource[0];
5564 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5565 if (vb) IWineD3DBuffer_Release(vb);
5566 This->stateBlock->streamIsUP = TRUE;
5567 This->stateBlock->streamOffset[0] = 0;
5568 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5570 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5571 This->stateBlock->baseVertexIndex = 0;
5572 This->stateBlock->loadBaseVertexIndex = 0;
5573 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5577 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5578 idxStride, pIndexData, MinVertexIndex);
5580 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5581 This->stateBlock->streamSource[0] = NULL;
5582 This->stateBlock->streamStride[0] = 0;
5583 ib = This->stateBlock->pIndexData;
5584 if(ib) {
5585 IWineD3DIndexBuffer_Release(ib);
5586 This->stateBlock->pIndexData = NULL;
5588 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5589 * SetStreamSource to specify a vertex buffer
5592 return WINED3D_OK;
5595 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5596 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5600 /* Mark the state dirty until we have nicer tracking
5601 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5602 * that value.
5604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5606 This->stateBlock->baseVertexIndex = 0;
5607 This->up_strided = DrawPrimStrideData;
5608 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5609 This->up_strided = NULL;
5610 return WINED3D_OK;
5613 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5614 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5615 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5618 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5620 /* Mark the state dirty until we have nicer tracking
5621 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5622 * that value.
5624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5626 This->stateBlock->streamIsUP = TRUE;
5627 This->stateBlock->baseVertexIndex = 0;
5628 This->up_strided = DrawPrimStrideData;
5629 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5630 This->up_strided = NULL;
5631 return WINED3D_OK;
5634 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5635 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5636 * not callable by the app directly no parameter validation checks are needed here.
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5639 WINED3DLOCKED_BOX src;
5640 WINED3DLOCKED_BOX dst;
5641 HRESULT hr;
5642 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5644 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5645 * dirtification to improve loading performance.
5647 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5648 if(FAILED(hr)) return hr;
5649 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5650 if(FAILED(hr)) {
5651 IWineD3DVolume_UnlockBox(pSourceVolume);
5652 return hr;
5655 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5657 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5658 if(FAILED(hr)) {
5659 IWineD3DVolume_UnlockBox(pSourceVolume);
5660 } else {
5661 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5663 return hr;
5666 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5667 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 HRESULT hr = WINED3D_OK;
5670 WINED3DRESOURCETYPE sourceType;
5671 WINED3DRESOURCETYPE destinationType;
5672 int i ,levels;
5674 /* TODO: think about moving the code into IWineD3DBaseTexture */
5676 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5678 /* verify that the source and destination textures aren't NULL */
5679 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5680 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5681 This, pSourceTexture, pDestinationTexture);
5682 hr = WINED3DERR_INVALIDCALL;
5685 if (pSourceTexture == pDestinationTexture) {
5686 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5687 This, pSourceTexture, pDestinationTexture);
5688 hr = WINED3DERR_INVALIDCALL;
5690 /* Verify that the source and destination textures are the same type */
5691 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5692 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5694 if (sourceType != destinationType) {
5695 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5696 This);
5697 hr = WINED3DERR_INVALIDCALL;
5700 /* check that both textures have the identical numbers of levels */
5701 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5702 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5703 hr = WINED3DERR_INVALIDCALL;
5706 if (WINED3D_OK == hr) {
5707 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5709 /* Make sure that the destination texture is loaded */
5710 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5712 /* Update every surface level of the texture */
5713 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5715 switch (sourceType) {
5716 case WINED3DRTYPE_TEXTURE:
5718 IWineD3DSurface *srcSurface;
5719 IWineD3DSurface *destSurface;
5721 for (i = 0 ; i < levels ; ++i) {
5722 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5723 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5724 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5725 IWineD3DSurface_Release(srcSurface);
5726 IWineD3DSurface_Release(destSurface);
5727 if (WINED3D_OK != hr) {
5728 WARN("(%p) : Call to update surface failed\n", This);
5729 return hr;
5733 break;
5734 case WINED3DRTYPE_CUBETEXTURE:
5736 IWineD3DSurface *srcSurface;
5737 IWineD3DSurface *destSurface;
5738 WINED3DCUBEMAP_FACES faceType;
5740 for (i = 0 ; i < levels ; ++i) {
5741 /* Update each cube face */
5742 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5743 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
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 srcSurface %p\n", srcSurface);
5749 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5750 if (WINED3D_OK != hr) {
5751 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5752 } else {
5753 TRACE("Got desrSurface %p\n", destSurface);
5755 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5756 IWineD3DSurface_Release(srcSurface);
5757 IWineD3DSurface_Release(destSurface);
5758 if (WINED3D_OK != hr) {
5759 WARN("(%p) : Call to update surface failed\n", This);
5760 return hr;
5765 break;
5767 case WINED3DRTYPE_VOLUMETEXTURE:
5769 IWineD3DVolume *srcVolume = NULL;
5770 IWineD3DVolume *destVolume = NULL;
5772 for (i = 0 ; i < levels ; ++i) {
5773 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5774 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5775 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5776 IWineD3DVolume_Release(srcVolume);
5777 IWineD3DVolume_Release(destVolume);
5778 if (WINED3D_OK != hr) {
5779 WARN("(%p) : Call to update volume failed\n", This);
5780 return hr;
5784 break;
5786 default:
5787 FIXME("(%p) : Unsupported source and destination type\n", This);
5788 hr = WINED3DERR_INVALIDCALL;
5792 return hr;
5795 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5796 IWineD3DSwapChain *swapChain;
5797 HRESULT hr;
5798 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5799 if(hr == WINED3D_OK) {
5800 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5801 IWineD3DSwapChain_Release(swapChain);
5803 return hr;
5806 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5808 IWineD3DBaseTextureImpl *texture;
5809 const struct GlPixelFormatDesc *gl_info;
5810 DWORD i;
5812 TRACE("(%p) : %p\n", This, pNumPasses);
5814 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5815 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5816 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5817 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5819 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5820 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5821 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5824 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5825 if(!texture) continue;
5826 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5827 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5829 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5830 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5831 return E_FAIL;
5833 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5834 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5835 return E_FAIL;
5837 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5838 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5839 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5840 return E_FAIL;
5844 /* return a sensible default */
5845 *pNumPasses = 1;
5847 TRACE("returning D3D_OK\n");
5848 return WINED3D_OK;
5851 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5853 int i;
5855 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5856 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5857 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5858 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5863 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5865 int j;
5866 UINT NewSize;
5867 PALETTEENTRY **palettes;
5869 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5871 if (PaletteNumber >= MAX_PALETTES) {
5872 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5873 return WINED3DERR_INVALIDCALL;
5876 if (PaletteNumber >= This->NumberOfPalettes) {
5877 NewSize = This->NumberOfPalettes;
5878 do {
5879 NewSize *= 2;
5880 } while(PaletteNumber >= NewSize);
5881 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5882 if (!palettes) {
5883 ERR("Out of memory!\n");
5884 return E_OUTOFMEMORY;
5886 This->palettes = palettes;
5887 This->NumberOfPalettes = NewSize;
5890 if (!This->palettes[PaletteNumber]) {
5891 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5892 if (!This->palettes[PaletteNumber]) {
5893 ERR("Out of memory!\n");
5894 return E_OUTOFMEMORY;
5898 for (j = 0; j < 256; ++j) {
5899 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5900 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5901 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5902 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5904 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5905 TRACE("(%p) : returning\n", This);
5906 return WINED3D_OK;
5909 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5911 int j;
5912 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5913 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5914 /* What happens in such situation isn't documented; Native seems to silently abort
5915 on such conditions. Return Invalid Call. */
5916 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5917 return WINED3DERR_INVALIDCALL;
5919 for (j = 0; j < 256; ++j) {
5920 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5921 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5922 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5923 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5925 TRACE("(%p) : returning\n", This);
5926 return WINED3D_OK;
5929 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5931 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5932 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5933 (tested with reference rasterizer). Return Invalid Call. */
5934 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5935 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5936 return WINED3DERR_INVALIDCALL;
5938 /*TODO: stateblocks */
5939 if (This->currentPalette != PaletteNumber) {
5940 This->currentPalette = PaletteNumber;
5941 dirtify_p8_texture_samplers(This);
5943 TRACE("(%p) : returning\n", This);
5944 return WINED3D_OK;
5947 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5949 if (PaletteNumber == NULL) {
5950 WARN("(%p) : returning Invalid Call\n", This);
5951 return WINED3DERR_INVALIDCALL;
5953 /*TODO: stateblocks */
5954 *PaletteNumber = This->currentPalette;
5955 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5956 return WINED3D_OK;
5959 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5961 static BOOL warned;
5962 if (!warned)
5964 FIXME("(%p) : stub\n", This);
5965 warned = TRUE;
5968 This->softwareVertexProcessing = bSoftware;
5969 return WINED3D_OK;
5973 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 static BOOL warned;
5976 if (!warned)
5978 FIXME("(%p) : stub\n", This);
5979 warned = TRUE;
5981 return This->softwareVertexProcessing;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 IWineD3DSwapChain *swapChain;
5988 HRESULT hr;
5990 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5992 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5993 if(hr == WINED3D_OK){
5994 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5995 IWineD3DSwapChain_Release(swapChain);
5996 }else{
5997 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5999 return hr;
6003 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6005 static BOOL warned;
6006 if(nSegments != 0.0f) {
6007 if (!warned)
6009 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6010 warned = TRUE;
6013 return WINED3D_OK;
6016 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6018 static BOOL warned;
6019 if (!warned)
6021 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6022 warned = TRUE;
6024 return 0.0f;
6027 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6029 /** TODO: remove casts to IWineD3DSurfaceImpl
6030 * NOTE: move code to surface to accomplish this
6031 ****************************************/
6032 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6033 int srcWidth, srcHeight;
6034 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6035 WINED3DFORMAT destFormat, srcFormat;
6036 UINT destSize;
6037 int srcLeft, destLeft, destTop;
6038 WINED3DPOOL srcPool, destPool;
6039 int offset = 0;
6040 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6041 glDescriptor *glDescription = NULL;
6042 GLenum dummy;
6043 int sampler;
6044 int bpp;
6045 CONVERT_TYPES convert = NO_CONVERSION;
6047 WINED3DSURFACE_DESC winedesc;
6049 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6050 memset(&winedesc, 0, sizeof(winedesc));
6051 winedesc.Width = &srcSurfaceWidth;
6052 winedesc.Height = &srcSurfaceHeight;
6053 winedesc.Pool = &srcPool;
6054 winedesc.Format = &srcFormat;
6056 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6058 winedesc.Width = &destSurfaceWidth;
6059 winedesc.Height = &destSurfaceHeight;
6060 winedesc.Pool = &destPool;
6061 winedesc.Format = &destFormat;
6062 winedesc.Size = &destSize;
6064 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6066 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6067 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6068 return WINED3DERR_INVALIDCALL;
6071 /* This call loads the opengl surface directly, instead of copying the surface to the
6072 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6073 * copy in sysmem and use regular surface loading.
6075 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6076 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6077 if(convert != NO_CONVERSION) {
6078 return IWineD3DSurface_BltFast(pDestinationSurface,
6079 pDestPoint ? pDestPoint->x : 0,
6080 pDestPoint ? pDestPoint->y : 0,
6081 pSourceSurface, pSourceRect, 0);
6084 if (destFormat == WINED3DFMT_UNKNOWN) {
6085 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6086 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6088 /* Get the update surface description */
6089 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6092 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6094 ENTER_GL();
6095 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6096 checkGLcall("glActiveTextureARB");
6097 LEAVE_GL();
6099 /* Make sure the surface is loaded and up to date */
6100 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6101 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6103 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6105 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6106 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6107 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6108 srcLeft = pSourceRect ? pSourceRect->left : 0;
6109 destLeft = pDestPoint ? pDestPoint->x : 0;
6110 destTop = pDestPoint ? pDestPoint->y : 0;
6113 /* This function doesn't support compressed textures
6114 the pitch is just bytesPerPixel * width */
6115 if(srcWidth != srcSurfaceWidth || srcLeft ){
6116 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6117 offset += srcLeft * pSrcSurface->bytesPerPixel;
6118 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6120 /* TODO DXT formats */
6122 if(pSourceRect != NULL && pSourceRect->top != 0){
6123 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6125 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6126 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
6127 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6129 /* Sanity check */
6130 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6132 /* need to lock the surface to get the data */
6133 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6136 ENTER_GL();
6138 /* TODO: Cube and volume support */
6139 if(rowoffset != 0){
6140 /* not a whole row so we have to do it a line at a time */
6141 int j;
6143 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6144 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6146 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6148 glTexSubImage2D(glDescription->target
6149 ,glDescription->level
6150 ,destLeft
6152 ,srcWidth
6154 ,glDescription->glFormat
6155 ,glDescription->glType
6156 ,data /* could be quicker using */
6158 data += rowoffset;
6161 } else { /* Full width, so just write out the whole texture */
6162 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6164 if (WINED3DFMT_DXT1 == destFormat ||
6165 WINED3DFMT_DXT2 == destFormat ||
6166 WINED3DFMT_DXT3 == destFormat ||
6167 WINED3DFMT_DXT4 == destFormat ||
6168 WINED3DFMT_DXT5 == destFormat) {
6169 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6170 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6171 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6172 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6173 } if (destFormat != srcFormat) {
6174 FIXME("Updating mixed format compressed texture is not curretly support\n");
6175 } else {
6176 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6177 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6179 } else {
6180 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6184 } else {
6185 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6186 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6189 checkGLcall("glTexSubImage2D");
6191 LEAVE_GL();
6193 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6194 sampler = This->rev_tex_unit_map[0];
6195 if (sampler != -1) {
6196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6199 return WINED3D_OK;
6202 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6204 struct WineD3DRectPatch *patch;
6205 GLenum old_primitive_type;
6206 unsigned int i;
6207 struct list *e;
6208 BOOL found;
6209 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6211 if(!(Handle || pRectPatchInfo)) {
6212 /* TODO: Write a test for the return value, thus the FIXME */
6213 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6214 return WINED3DERR_INVALIDCALL;
6217 if(Handle) {
6218 i = PATCHMAP_HASHFUNC(Handle);
6219 found = FALSE;
6220 LIST_FOR_EACH(e, &This->patches[i]) {
6221 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6222 if(patch->Handle == Handle) {
6223 found = TRUE;
6224 break;
6228 if(!found) {
6229 TRACE("Patch does not exist. Creating a new one\n");
6230 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6231 patch->Handle = Handle;
6232 list_add_head(&This->patches[i], &patch->entry);
6233 } else {
6234 TRACE("Found existing patch %p\n", patch);
6236 } else {
6237 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6238 * attributes we have to tesselate, read back, and draw. This needs a patch
6239 * management structure instance. Create one.
6241 * A possible improvement is to check if a vertex shader is used, and if not directly
6242 * draw the patch.
6244 FIXME("Drawing an uncached patch. This is slow\n");
6245 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6248 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6249 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6250 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6251 HRESULT hr;
6252 TRACE("Tesselation density or patch info changed, retesselating\n");
6254 if(pRectPatchInfo) {
6255 patch->RectPatchInfo = *pRectPatchInfo;
6257 patch->numSegs[0] = pNumSegs[0];
6258 patch->numSegs[1] = pNumSegs[1];
6259 patch->numSegs[2] = pNumSegs[2];
6260 patch->numSegs[3] = pNumSegs[3];
6262 hr = tesselate_rectpatch(This, patch);
6263 if(FAILED(hr)) {
6264 WARN("Patch tesselation failed\n");
6266 /* Do not release the handle to store the params of the patch */
6267 if(!Handle) {
6268 HeapFree(GetProcessHeap(), 0, patch);
6270 return hr;
6274 This->currentPatch = patch;
6275 old_primitive_type = This->stateBlock->gl_primitive_type;
6276 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6277 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6278 This->stateBlock->gl_primitive_type = old_primitive_type;
6279 This->currentPatch = NULL;
6281 /* Destroy uncached patches */
6282 if(!Handle) {
6283 HeapFree(GetProcessHeap(), 0, patch->mem);
6284 HeapFree(GetProcessHeap(), 0, patch);
6286 return WINED3D_OK;
6289 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6291 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6292 FIXME("(%p) : Stub\n", This);
6293 return WINED3D_OK;
6296 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 int i;
6299 struct WineD3DRectPatch *patch;
6300 struct list *e;
6301 TRACE("(%p) Handle(%d)\n", This, Handle);
6303 i = PATCHMAP_HASHFUNC(Handle);
6304 LIST_FOR_EACH(e, &This->patches[i]) {
6305 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6306 if(patch->Handle == Handle) {
6307 TRACE("Deleting patch %p\n", patch);
6308 list_remove(&patch->entry);
6309 HeapFree(GetProcessHeap(), 0, patch->mem);
6310 HeapFree(GetProcessHeap(), 0, patch);
6311 return WINED3D_OK;
6315 /* TODO: Write a test for the return value */
6316 FIXME("Attempt to destroy nonexistent patch\n");
6317 return WINED3DERR_INVALIDCALL;
6320 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6321 HRESULT hr;
6322 IWineD3DSwapChain *swapchain;
6324 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6325 if (SUCCEEDED(hr)) {
6326 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6327 return swapchain;
6330 return NULL;
6333 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6334 const WINED3DRECT *rect, const float color[4])
6336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6337 IWineD3DSwapChain *swapchain;
6339 swapchain = get_swapchain(surface);
6340 if (swapchain) {
6341 GLenum buffer;
6343 TRACE("Surface %p is onscreen\n", surface);
6345 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6346 ENTER_GL();
6347 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6348 buffer = surface_get_gl_buffer(surface, swapchain);
6349 glDrawBuffer(buffer);
6350 checkGLcall("glDrawBuffer()");
6351 } else {
6352 TRACE("Surface %p is offscreen\n", surface);
6354 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6355 ENTER_GL();
6356 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6357 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6358 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6359 checkGLcall("glFramebufferRenderbufferEXT");
6362 if (rect) {
6363 glEnable(GL_SCISSOR_TEST);
6364 if(!swapchain) {
6365 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6366 } else {
6367 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6368 rect->x2 - rect->x1, rect->y2 - rect->y1);
6370 checkGLcall("glScissor");
6371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6372 } else {
6373 glDisable(GL_SCISSOR_TEST);
6375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6377 glDisable(GL_BLEND);
6378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6380 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6383 glClearColor(color[0], color[1], color[2], color[3]);
6384 glClear(GL_COLOR_BUFFER_BIT);
6385 checkGLcall("glClear");
6387 if (This->activeContext->current_fbo) {
6388 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6389 } else {
6390 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6391 checkGLcall("glBindFramebuffer()");
6394 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6395 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6396 glDrawBuffer(GL_BACK);
6397 checkGLcall("glDrawBuffer()");
6400 LEAVE_GL();
6403 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6404 unsigned int r, g, b, a;
6405 DWORD ret;
6407 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6408 destfmt == WINED3DFMT_R8G8B8)
6409 return color;
6411 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6413 a = (color & 0xff000000) >> 24;
6414 r = (color & 0x00ff0000) >> 16;
6415 g = (color & 0x0000ff00) >> 8;
6416 b = (color & 0x000000ff) >> 0;
6418 switch(destfmt)
6420 case WINED3DFMT_R5G6B5:
6421 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6422 r = (r * 32) / 256;
6423 g = (g * 64) / 256;
6424 b = (b * 32) / 256;
6425 ret = r << 11;
6426 ret |= g << 5;
6427 ret |= b;
6428 TRACE("Returning %08x\n", ret);
6429 return ret;
6431 case WINED3DFMT_X1R5G5B5:
6432 case WINED3DFMT_A1R5G5B5:
6433 a = (a * 2) / 256;
6434 r = (r * 32) / 256;
6435 g = (g * 32) / 256;
6436 b = (b * 32) / 256;
6437 ret = a << 15;
6438 ret |= r << 10;
6439 ret |= g << 5;
6440 ret |= b << 0;
6441 TRACE("Returning %08x\n", ret);
6442 return ret;
6444 case WINED3DFMT_A8_UNORM:
6445 TRACE("Returning %08x\n", a);
6446 return a;
6448 case WINED3DFMT_X4R4G4B4:
6449 case WINED3DFMT_A4R4G4B4:
6450 a = (a * 16) / 256;
6451 r = (r * 16) / 256;
6452 g = (g * 16) / 256;
6453 b = (b * 16) / 256;
6454 ret = a << 12;
6455 ret |= r << 8;
6456 ret |= g << 4;
6457 ret |= b << 0;
6458 TRACE("Returning %08x\n", ret);
6459 return ret;
6461 case WINED3DFMT_R3G3B2:
6462 r = (r * 8) / 256;
6463 g = (g * 8) / 256;
6464 b = (b * 4) / 256;
6465 ret = r << 5;
6466 ret |= g << 2;
6467 ret |= b << 0;
6468 TRACE("Returning %08x\n", ret);
6469 return ret;
6471 case WINED3DFMT_X8B8G8R8:
6472 case WINED3DFMT_R8G8B8A8_UNORM:
6473 ret = a << 24;
6474 ret |= b << 16;
6475 ret |= g << 8;
6476 ret |= r << 0;
6477 TRACE("Returning %08x\n", ret);
6478 return ret;
6480 case WINED3DFMT_A2R10G10B10:
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 |= r << 20;
6487 ret |= g << 10;
6488 ret |= b << 0;
6489 TRACE("Returning %08x\n", ret);
6490 return ret;
6492 case WINED3DFMT_R10G10B10A2_UNORM:
6493 a = (a * 4) / 256;
6494 r = (r * 1024) / 256;
6495 g = (g * 1024) / 256;
6496 b = (b * 1024) / 256;
6497 ret = a << 30;
6498 ret |= b << 20;
6499 ret |= g << 10;
6500 ret |= r << 0;
6501 TRACE("Returning %08x\n", ret);
6502 return ret;
6504 default:
6505 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6506 return 0;
6510 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6512 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6513 WINEDDBLTFX BltFx;
6514 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6516 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6517 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6518 return WINED3DERR_INVALIDCALL;
6521 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6522 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6523 color_fill_fbo(iface, pSurface, pRect, c);
6524 return WINED3D_OK;
6525 } else {
6526 /* Just forward this to the DirectDraw blitting engine */
6527 memset(&BltFx, 0, sizeof(BltFx));
6528 BltFx.dwSize = sizeof(BltFx);
6529 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6530 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6531 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6535 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6536 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6538 IWineD3DResource *resource;
6539 IWineD3DSurface *surface;
6540 HRESULT hr;
6542 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6543 if (FAILED(hr))
6545 ERR("Failed to get resource, hr %#x\n", hr);
6546 return;
6549 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6551 FIXME("Only supported on surface resources\n");
6552 IWineD3DResource_Release(resource);
6553 return;
6556 surface = (IWineD3DSurface *)resource;
6558 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6560 color_fill_fbo(iface, surface, NULL, color);
6562 else
6564 WINEDDBLTFX BltFx;
6565 WINED3DCOLOR c;
6567 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6569 c = ((DWORD)(color[2] * 255.0));
6570 c |= ((DWORD)(color[1] * 255.0)) << 8;
6571 c |= ((DWORD)(color[0] * 255.0)) << 16;
6572 c |= ((DWORD)(color[3] * 255.0)) << 24;
6574 /* Just forward this to the DirectDraw blitting engine */
6575 memset(&BltFx, 0, sizeof(BltFx));
6576 BltFx.dwSize = sizeof(BltFx);
6577 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format);
6578 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6579 if (FAILED(hr))
6581 ERR("Blt failed, hr %#x\n", hr);
6585 IWineD3DResource_Release(resource);
6588 /* rendertarget and depth stencil functions */
6589 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6592 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6593 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6594 return WINED3DERR_INVALIDCALL;
6597 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6598 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6599 /* Note inc ref on returned surface */
6600 if(*ppRenderTarget != NULL)
6601 IWineD3DSurface_AddRef(*ppRenderTarget);
6602 return WINED3D_OK;
6605 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6607 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6608 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6609 IWineD3DSwapChainImpl *Swapchain;
6610 HRESULT hr;
6612 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6614 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6615 if(hr != WINED3D_OK) {
6616 ERR("Can't get the swapchain\n");
6617 return hr;
6620 /* Make sure to release the swapchain */
6621 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6623 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6624 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6625 return WINED3DERR_INVALIDCALL;
6627 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6628 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6629 return WINED3DERR_INVALIDCALL;
6632 if(Swapchain->frontBuffer != Front) {
6633 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6635 if(Swapchain->frontBuffer)
6636 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6637 Swapchain->frontBuffer = Front;
6639 if(Swapchain->frontBuffer) {
6640 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6644 if(Back && !Swapchain->backBuffer) {
6645 /* We need memory for the back buffer array - only one back buffer this way */
6646 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6647 if(!Swapchain->backBuffer) {
6648 ERR("Out of memory\n");
6649 return E_OUTOFMEMORY;
6653 if(Swapchain->backBuffer[0] != Back) {
6654 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6656 /* What to do about the context here in the case of multithreading? Not sure.
6657 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6659 ENTER_GL();
6660 if(!Swapchain->backBuffer[0]) {
6661 /* GL was told to draw to the front buffer at creation,
6662 * undo that
6664 glDrawBuffer(GL_BACK);
6665 checkGLcall("glDrawBuffer(GL_BACK)");
6666 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6667 Swapchain->presentParms.BackBufferCount = 1;
6668 } else if (!Back) {
6669 /* That makes problems - disable for now */
6670 /* glDrawBuffer(GL_FRONT); */
6671 checkGLcall("glDrawBuffer(GL_FRONT)");
6672 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6673 Swapchain->presentParms.BackBufferCount = 0;
6675 LEAVE_GL();
6677 if(Swapchain->backBuffer[0])
6678 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6679 Swapchain->backBuffer[0] = Back;
6681 if(Swapchain->backBuffer[0]) {
6682 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6683 } else {
6684 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6685 Swapchain->backBuffer = NULL;
6690 return WINED3D_OK;
6693 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6695 *ppZStencilSurface = This->stencilBufferTarget;
6696 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6698 if(*ppZStencilSurface != NULL) {
6699 /* Note inc ref on returned surface */
6700 IWineD3DSurface_AddRef(*ppZStencilSurface);
6701 return WINED3D_OK;
6702 } else {
6703 return WINED3DERR_NOTFOUND;
6707 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6708 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6711 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6712 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6713 GLenum gl_filter;
6714 POINT offset = {0, 0};
6716 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6717 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6718 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6719 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6721 switch (filter) {
6722 case WINED3DTEXF_LINEAR:
6723 gl_filter = GL_LINEAR;
6724 break;
6726 default:
6727 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6728 case WINED3DTEXF_NONE:
6729 case WINED3DTEXF_POINT:
6730 gl_filter = GL_NEAREST;
6731 break;
6734 /* Attach src surface to src fbo */
6735 src_swapchain = get_swapchain(src_surface);
6736 if (src_swapchain) {
6737 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6739 TRACE("Source surface %p is onscreen\n", src_surface);
6740 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6741 /* Make sure the drawable is up to date. In the offscreen case
6742 * attach_surface_fbo() implicitly takes care of this. */
6743 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6745 if(buffer == GL_FRONT) {
6746 RECT windowsize;
6747 UINT h;
6748 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6749 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6750 h = windowsize.bottom - windowsize.top;
6751 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6752 src_rect->y1 = offset.y + h - src_rect->y1;
6753 src_rect->y2 = offset.y + h - src_rect->y2;
6754 } else {
6755 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6756 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6759 ENTER_GL();
6760 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6761 glReadBuffer(buffer);
6762 checkGLcall("glReadBuffer()");
6763 } else {
6764 TRACE("Source surface %p is offscreen\n", src_surface);
6765 ENTER_GL();
6766 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6767 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6768 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6769 checkGLcall("glReadBuffer()");
6770 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6771 checkGLcall("glFramebufferRenderbufferEXT");
6773 LEAVE_GL();
6775 /* Attach dst surface to dst fbo */
6776 dst_swapchain = get_swapchain(dst_surface);
6777 if (dst_swapchain) {
6778 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6780 TRACE("Destination surface %p is onscreen\n", dst_surface);
6781 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6782 /* Make sure the drawable is up to date. In the offscreen case
6783 * attach_surface_fbo() implicitly takes care of this. */
6784 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6786 if(buffer == GL_FRONT) {
6787 RECT windowsize;
6788 UINT h;
6789 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6790 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6791 h = windowsize.bottom - windowsize.top;
6792 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6793 dst_rect->y1 = offset.y + h - dst_rect->y1;
6794 dst_rect->y2 = offset.y + h - dst_rect->y2;
6795 } else {
6796 /* Screen coords = window coords, surface height = window height */
6797 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6798 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6801 ENTER_GL();
6802 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6803 glDrawBuffer(buffer);
6804 checkGLcall("glDrawBuffer()");
6805 } else {
6806 TRACE("Destination surface %p is offscreen\n", dst_surface);
6808 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6809 if(!src_swapchain) {
6810 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6813 ENTER_GL();
6814 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6815 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6816 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6817 checkGLcall("glDrawBuffer()");
6818 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6819 checkGLcall("glFramebufferRenderbufferEXT");
6821 glDisable(GL_SCISSOR_TEST);
6822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6824 if (flip) {
6825 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6826 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6827 checkGLcall("glBlitFramebuffer()");
6828 } else {
6829 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6830 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6831 checkGLcall("glBlitFramebuffer()");
6834 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6836 if (This->activeContext->current_fbo) {
6837 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6838 } else {
6839 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6840 checkGLcall("glBindFramebuffer()");
6843 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6844 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6845 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6846 glDrawBuffer(GL_BACK);
6847 checkGLcall("glDrawBuffer()");
6849 LEAVE_GL();
6852 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6854 WINED3DVIEWPORT viewport;
6856 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6858 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6859 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6860 This, RenderTargetIndex, GL_LIMITS(buffers));
6861 return WINED3DERR_INVALIDCALL;
6864 /* MSDN says that null disables the render target
6865 but a device must always be associated with a render target
6866 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6868 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6869 FIXME("Trying to set render target 0 to NULL\n");
6870 return WINED3DERR_INVALIDCALL;
6872 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6873 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);
6874 return WINED3DERR_INVALIDCALL;
6877 /* If we are trying to set what we already have, don't bother */
6878 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6879 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6880 return WINED3D_OK;
6882 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6883 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6884 This->render_targets[RenderTargetIndex] = pRenderTarget;
6886 /* Render target 0 is special */
6887 if(RenderTargetIndex == 0) {
6888 /* Finally, reset the viewport as the MSDN states. */
6889 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6890 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6891 viewport.X = 0;
6892 viewport.Y = 0;
6893 viewport.MaxZ = 1.0f;
6894 viewport.MinZ = 0.0f;
6895 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6896 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6897 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6901 return WINED3D_OK;
6904 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6906 HRESULT hr = WINED3D_OK;
6907 IWineD3DSurface *tmp;
6909 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6911 if (pNewZStencil == This->stencilBufferTarget) {
6912 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6913 } else {
6914 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6915 * depending on the renter target implementation being used.
6916 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6917 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6918 * stencil buffer and incur an extra memory overhead
6919 ******************************************************/
6921 if (This->stencilBufferTarget) {
6922 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6923 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6924 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6925 } else {
6926 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6927 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6928 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6932 tmp = This->stencilBufferTarget;
6933 This->stencilBufferTarget = pNewZStencil;
6934 /* should we be calling the parent or the wined3d surface? */
6935 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6936 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6937 hr = WINED3D_OK;
6939 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6940 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6947 return hr;
6950 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6951 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6953 /* TODO: the use of Impl is deprecated. */
6954 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6955 WINED3DLOCKED_RECT lockedRect;
6957 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6959 /* some basic validation checks */
6960 if(This->cursorTexture) {
6961 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6962 ENTER_GL();
6963 glDeleteTextures(1, &This->cursorTexture);
6964 LEAVE_GL();
6965 This->cursorTexture = 0;
6968 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6969 This->haveHardwareCursor = TRUE;
6970 else
6971 This->haveHardwareCursor = FALSE;
6973 if(pCursorBitmap) {
6974 WINED3DLOCKED_RECT rect;
6976 /* MSDN: Cursor must be A8R8G8B8 */
6977 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6978 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6979 return WINED3DERR_INVALIDCALL;
6982 /* MSDN: Cursor must be smaller than the display mode */
6983 if(pSur->currentDesc.Width > This->ddraw_width ||
6984 pSur->currentDesc.Height > This->ddraw_height) {
6985 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);
6986 return WINED3DERR_INVALIDCALL;
6989 if (!This->haveHardwareCursor) {
6990 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6992 /* Do not store the surface's pointer because the application may
6993 * release it after setting the cursor image. Windows doesn't
6994 * addref the set surface, so we can't do this either without
6995 * creating circular refcount dependencies. Copy out the gl texture
6996 * instead.
6998 This->cursorWidth = pSur->currentDesc.Width;
6999 This->cursorHeight = pSur->currentDesc.Height;
7000 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7002 const struct GlPixelFormatDesc *glDesc;
7003 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
7004 char *mem, *bits = rect.pBits;
7005 GLint intfmt = glDesc->glInternal;
7006 GLint format = glDesc->glFormat;
7007 GLint type = glDesc->glType;
7008 INT height = This->cursorHeight;
7009 INT width = This->cursorWidth;
7010 INT bpp = tableEntry->bpp;
7011 INT i, sampler;
7013 /* Reformat the texture memory (pitch and width can be
7014 * different) */
7015 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7016 for(i = 0; i < height; i++)
7017 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7018 IWineD3DSurface_UnlockRect(pCursorBitmap);
7019 ENTER_GL();
7021 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7022 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7023 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7026 /* Make sure that a proper texture unit is selected */
7027 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7028 checkGLcall("glActiveTextureARB");
7029 sampler = This->rev_tex_unit_map[0];
7030 if (sampler != -1) {
7031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7033 /* Create a new cursor texture */
7034 glGenTextures(1, &This->cursorTexture);
7035 checkGLcall("glGenTextures");
7036 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7037 checkGLcall("glBindTexture");
7038 /* Copy the bitmap memory into the cursor texture */
7039 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7040 HeapFree(GetProcessHeap(), 0, mem);
7041 checkGLcall("glTexImage2D");
7043 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7044 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7045 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7048 LEAVE_GL();
7050 else
7052 FIXME("A cursor texture was not returned.\n");
7053 This->cursorTexture = 0;
7056 else
7058 /* Draw a hardware cursor */
7059 ICONINFO cursorInfo;
7060 HCURSOR cursor;
7061 /* Create and clear maskBits because it is not needed for
7062 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7063 * chunks. */
7064 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7065 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7066 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7067 WINED3DLOCK_NO_DIRTY_UPDATE |
7068 WINED3DLOCK_READONLY
7070 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7071 pSur->currentDesc.Height);
7073 cursorInfo.fIcon = FALSE;
7074 cursorInfo.xHotspot = XHotSpot;
7075 cursorInfo.yHotspot = YHotSpot;
7076 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7077 pSur->currentDesc.Height, 1,
7078 1, &maskBits);
7079 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7080 pSur->currentDesc.Height, 1,
7081 32, lockedRect.pBits);
7082 IWineD3DSurface_UnlockRect(pCursorBitmap);
7083 /* Create our cursor and clean up. */
7084 cursor = CreateIconIndirect(&cursorInfo);
7085 SetCursor(cursor);
7086 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7087 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7088 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7089 This->hardwareCursor = cursor;
7090 HeapFree(GetProcessHeap(), 0, maskBits);
7094 This->xHotSpot = XHotSpot;
7095 This->yHotSpot = YHotSpot;
7096 return WINED3D_OK;
7099 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7101 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7103 This->xScreenSpace = XScreenSpace;
7104 This->yScreenSpace = YScreenSpace;
7106 return;
7110 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7112 BOOL oldVisible = This->bCursorVisible;
7113 POINT pt;
7115 TRACE("(%p) : visible(%d)\n", This, bShow);
7118 * When ShowCursor is first called it should make the cursor appear at the OS's last
7119 * known cursor position. Because of this, some applications just repetitively call
7120 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7122 GetCursorPos(&pt);
7123 This->xScreenSpace = pt.x;
7124 This->yScreenSpace = pt.y;
7126 if (This->haveHardwareCursor) {
7127 This->bCursorVisible = bShow;
7128 if (bShow)
7129 SetCursor(This->hardwareCursor);
7130 else
7131 SetCursor(NULL);
7133 else
7135 if (This->cursorTexture)
7136 This->bCursorVisible = bShow;
7139 return oldVisible;
7142 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7144 IWineD3DResourceImpl *resource;
7145 TRACE("(%p) : state (%u)\n", This, This->state);
7147 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7148 switch (This->state) {
7149 case WINED3D_OK:
7150 return WINED3D_OK;
7151 case WINED3DERR_DEVICELOST:
7153 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7154 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7155 return WINED3DERR_DEVICENOTRESET;
7157 return WINED3DERR_DEVICELOST;
7159 case WINED3DERR_DRIVERINTERNALERROR:
7160 return WINED3DERR_DRIVERINTERNALERROR;
7163 /* Unknown state */
7164 return WINED3DERR_DRIVERINTERNALERROR;
7168 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7170 /** FIXME: Resource tracking needs to be done,
7171 * The closes we can do to this is set the priorities of all managed textures low
7172 * and then reset them.
7173 ***********************************************************/
7174 FIXME("(%p) : stub\n", This);
7175 return WINED3D_OK;
7178 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7180 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7182 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7183 if(surface->Flags & SFLAG_DIBSECTION) {
7184 /* Release the DC */
7185 SelectObject(surface->hDC, surface->dib.holdbitmap);
7186 DeleteDC(surface->hDC);
7187 /* Release the DIB section */
7188 DeleteObject(surface->dib.DIBsection);
7189 surface->dib.bitmap_data = NULL;
7190 surface->resource.allocatedMemory = NULL;
7191 surface->Flags &= ~SFLAG_DIBSECTION;
7193 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7194 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7195 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7196 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7197 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7198 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7199 } else {
7200 surface->pow2Width = surface->pow2Height = 1;
7201 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7202 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7204 surface->glRect.left = 0;
7205 surface->glRect.top = 0;
7206 surface->glRect.right = surface->pow2Width;
7207 surface->glRect.bottom = surface->pow2Height;
7209 if(surface->glDescription.textureName) {
7210 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7211 ENTER_GL();
7212 glDeleteTextures(1, &surface->glDescription.textureName);
7213 LEAVE_GL();
7214 surface->glDescription.textureName = 0;
7215 surface->Flags &= ~SFLAG_CLIENT;
7217 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7218 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7219 surface->Flags |= SFLAG_NONPOW2;
7220 } else {
7221 surface->Flags &= ~SFLAG_NONPOW2;
7223 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7224 surface->resource.allocatedMemory = NULL;
7225 surface->resource.heapMemory = NULL;
7226 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7227 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7228 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7229 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7230 } else {
7231 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7235 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7236 TRACE("Unloading resource %p\n", resource);
7237 IWineD3DResource_UnLoad(resource);
7238 IWineD3DResource_Release(resource);
7239 return S_OK;
7242 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7244 UINT i, count;
7245 WINED3DDISPLAYMODE m;
7246 HRESULT hr;
7248 /* All Windowed modes are supported, as is leaving the current mode */
7249 if(pp->Windowed) return TRUE;
7250 if(!pp->BackBufferWidth) return TRUE;
7251 if(!pp->BackBufferHeight) return TRUE;
7253 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7254 for(i = 0; i < count; i++) {
7255 memset(&m, 0, sizeof(m));
7256 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7257 if(FAILED(hr)) {
7258 ERR("EnumAdapterModes failed\n");
7260 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7261 /* Mode found, it is supported */
7262 return TRUE;
7265 /* Mode not found -> not supported */
7266 return FALSE;
7269 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7271 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7272 UINT i;
7273 IWineD3DBaseShaderImpl *shader;
7275 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7276 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7277 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7280 ENTER_GL();
7281 if(This->depth_blt_texture) {
7282 glDeleteTextures(1, &This->depth_blt_texture);
7283 This->depth_blt_texture = 0;
7285 if (This->depth_blt_rb) {
7286 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7287 This->depth_blt_rb = 0;
7288 This->depth_blt_rb_w = 0;
7289 This->depth_blt_rb_h = 0;
7291 LEAVE_GL();
7293 This->blitter->free_private(iface);
7294 This->frag_pipe->free_private(iface);
7295 This->shader_backend->shader_free_private(iface);
7297 ENTER_GL();
7298 for (i = 0; i < GL_LIMITS(textures); i++) {
7299 /* Textures are recreated below */
7300 glDeleteTextures(1, &This->dummyTextureName[i]);
7301 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7302 This->dummyTextureName[i] = 0;
7304 LEAVE_GL();
7306 while(This->numContexts) {
7307 DestroyContext(This, This->contexts[0]);
7309 This->activeContext = NULL;
7310 HeapFree(GetProcessHeap(), 0, swapchain->context);
7311 swapchain->context = NULL;
7312 swapchain->num_contexts = 0;
7315 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7317 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7318 HRESULT hr;
7319 IWineD3DSurfaceImpl *target;
7321 /* Recreate the primary swapchain's context */
7322 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7323 if(swapchain->backBuffer) {
7324 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7325 } else {
7326 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7328 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7329 &swapchain->presentParms);
7330 swapchain->num_contexts = 1;
7331 This->activeContext = swapchain->context[0];
7333 create_dummy_textures(This);
7335 hr = This->shader_backend->shader_alloc_private(iface);
7336 if(FAILED(hr)) {
7337 ERR("Failed to recreate shader private data\n");
7338 goto err_out;
7340 hr = This->frag_pipe->alloc_private(iface);
7341 if(FAILED(hr)) {
7342 TRACE("Fragment pipeline private data couldn't be allocated\n");
7343 goto err_out;
7345 hr = This->blitter->alloc_private(iface);
7346 if(FAILED(hr)) {
7347 TRACE("Blitter private data couldn't be allocated\n");
7348 goto err_out;
7351 return WINED3D_OK;
7353 err_out:
7354 This->blitter->free_private(iface);
7355 This->frag_pipe->free_private(iface);
7356 This->shader_backend->shader_free_private(iface);
7357 return hr;
7360 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7362 IWineD3DSwapChainImpl *swapchain;
7363 HRESULT hr;
7364 BOOL DisplayModeChanged = FALSE;
7365 WINED3DDISPLAYMODE mode;
7366 TRACE("(%p)\n", This);
7368 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7369 if(FAILED(hr)) {
7370 ERR("Failed to get the first implicit swapchain\n");
7371 return hr;
7374 if(!is_display_mode_supported(This, pPresentationParameters)) {
7375 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7376 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7377 pPresentationParameters->BackBufferHeight);
7378 return WINED3DERR_INVALIDCALL;
7381 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7382 * on an existing gl context, so there's no real need for recreation.
7384 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7386 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7388 TRACE("New params:\n");
7389 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7390 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7391 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7392 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7393 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7394 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7395 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7396 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7397 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7398 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7399 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7400 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7401 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7403 /* No special treatment of these parameters. Just store them */
7404 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7405 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7406 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7407 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7409 /* What to do about these? */
7410 if(pPresentationParameters->BackBufferCount != 0 &&
7411 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7412 ERR("Cannot change the back buffer count yet\n");
7414 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7415 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7416 ERR("Cannot change the back buffer format yet\n");
7418 if(pPresentationParameters->hDeviceWindow != NULL &&
7419 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7420 ERR("Cannot change the device window yet\n");
7422 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7423 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7424 return WINED3DERR_INVALIDCALL;
7427 /* Reset the depth stencil */
7428 if (pPresentationParameters->EnableAutoDepthStencil)
7429 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7430 else
7431 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7433 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7435 if(pPresentationParameters->Windowed) {
7436 mode.Width = swapchain->orig_width;
7437 mode.Height = swapchain->orig_height;
7438 mode.RefreshRate = 0;
7439 mode.Format = swapchain->presentParms.BackBufferFormat;
7440 } else {
7441 mode.Width = pPresentationParameters->BackBufferWidth;
7442 mode.Height = pPresentationParameters->BackBufferHeight;
7443 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7444 mode.Format = swapchain->presentParms.BackBufferFormat;
7447 /* Should Width == 800 && Height == 0 set 800x600? */
7448 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7449 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7450 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7452 UINT i;
7454 if(!pPresentationParameters->Windowed) {
7455 DisplayModeChanged = TRUE;
7457 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7458 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7460 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7461 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7462 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7464 if(This->auto_depth_stencil_buffer) {
7465 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7469 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7470 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7471 DisplayModeChanged) {
7473 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7475 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7476 if(swapchain->presentParms.Windowed) {
7477 /* switch from windowed to fs */
7478 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7479 pPresentationParameters->BackBufferWidth,
7480 pPresentationParameters->BackBufferHeight);
7481 } else {
7482 /* Fullscreen -> fullscreen mode change */
7483 MoveWindow(swapchain->win_handle, 0, 0,
7484 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7485 TRUE);
7487 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7488 /* Fullscreen -> windowed switch */
7489 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7491 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7492 } else if(!pPresentationParameters->Windowed) {
7493 DWORD style = This->style, exStyle = This->exStyle;
7494 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7495 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7496 * Reset to clear up their mess. Guild Wars also loses the device during that.
7498 This->style = 0;
7499 This->exStyle = 0;
7500 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7501 pPresentationParameters->BackBufferWidth,
7502 pPresentationParameters->BackBufferHeight);
7503 This->style = style;
7504 This->exStyle = exStyle;
7507 TRACE("Resetting stateblock\n");
7508 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7509 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7511 /* Note: No parent needed for initial internal stateblock */
7512 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7513 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7514 else TRACE("Created stateblock %p\n", This->stateBlock);
7515 This->updateStateBlock = This->stateBlock;
7516 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7518 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7519 if(FAILED(hr)) {
7520 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7523 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7524 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7526 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7527 * first use
7529 return hr;
7532 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7534 /** FIXME: always true at the moment **/
7535 if(!bEnableDialogs) {
7536 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7538 return WINED3D_OK;
7542 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7544 TRACE("(%p) : pParameters %p\n", This, pParameters);
7546 *pParameters = This->createParms;
7547 return WINED3D_OK;
7550 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7551 IWineD3DSwapChain *swapchain;
7553 TRACE("Relaying to swapchain\n");
7555 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7556 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7557 IWineD3DSwapChain_Release(swapchain);
7559 return;
7562 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7563 IWineD3DSwapChain *swapchain;
7565 TRACE("Relaying to swapchain\n");
7567 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7568 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7569 IWineD3DSwapChain_Release(swapchain);
7571 return;
7575 /** ********************************************************
7576 * Notification functions
7577 ** ********************************************************/
7578 /** This function must be called in the release of a resource when ref == 0,
7579 * the contents of resource must still be correct,
7580 * any handles to other resource held by the caller must be closed
7581 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7582 *****************************************************/
7583 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7586 TRACE("(%p) : Adding Resource %p\n", This, resource);
7587 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7590 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7593 TRACE("(%p) : Removing resource %p\n", This, resource);
7595 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7599 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7601 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7602 int counter;
7604 TRACE("(%p) : resource %p\n", This, resource);
7606 context_resource_released(iface, resource, type);
7608 switch (type) {
7609 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7610 case WINED3DRTYPE_SURFACE: {
7611 unsigned int i;
7613 /* Cleanup any FBO attachments if d3d is enabled */
7614 if(This->d3d_initialized) {
7615 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7616 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7618 TRACE("Last active render target destroyed\n");
7619 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7620 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7621 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7622 * and the lastActiveRenderTarget member shouldn't matter
7624 if(swapchain) {
7625 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7626 TRACE("Activating primary back buffer\n");
7627 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7628 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7629 /* Single buffering environment */
7630 TRACE("Activating primary front buffer\n");
7631 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7632 } else {
7633 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7634 /* Implicit render target destroyed, that means the device is being destroyed
7635 * whatever we set here, it shouldn't matter
7637 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7639 } else {
7640 /* May happen during ddraw uninitialization */
7641 TRACE("Render target set, but swapchain does not exist!\n");
7642 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7646 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7647 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7648 This->render_targets[i] = NULL;
7651 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7652 This->stencilBufferTarget = NULL;
7656 break;
7658 case WINED3DRTYPE_TEXTURE:
7659 case WINED3DRTYPE_CUBETEXTURE:
7660 case WINED3DRTYPE_VOLUMETEXTURE:
7661 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7662 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7663 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7664 This->stateBlock->textures[counter] = NULL;
7666 if (This->updateStateBlock != This->stateBlock ){
7667 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7668 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7669 This->updateStateBlock->textures[counter] = NULL;
7673 break;
7674 case WINED3DRTYPE_VOLUME:
7675 /* TODO: nothing really? */
7676 break;
7677 case WINED3DRTYPE_VERTEXBUFFER:
7679 int streamNumber;
7680 TRACE("Cleaning up stream pointers\n");
7682 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7683 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7684 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7686 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7687 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7688 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7689 This->updateStateBlock->streamSource[streamNumber] = 0;
7690 /* Set changed flag? */
7693 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) */
7694 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7695 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7696 This->stateBlock->streamSource[streamNumber] = 0;
7701 break;
7702 case WINED3DRTYPE_INDEXBUFFER:
7703 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7704 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7705 This->updateStateBlock->pIndexData = NULL;
7708 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7709 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7710 This->stateBlock->pIndexData = NULL;
7713 break;
7715 case WINED3DRTYPE_BUFFER:
7716 /* Nothing to do, yet.*/
7717 break;
7719 default:
7720 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7721 break;
7725 /* Remove the resource from the resourceStore */
7726 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7728 TRACE("Resource released\n");
7732 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7734 IWineD3DResourceImpl *resource, *cursor;
7735 HRESULT ret;
7736 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7738 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7739 TRACE("enumerating resource %p\n", resource);
7740 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7741 ret = pCallback((IWineD3DResource *) resource, pData);
7742 if(ret == S_FALSE) {
7743 TRACE("Canceling enumeration\n");
7744 break;
7747 return WINED3D_OK;
7750 /**********************************************************
7751 * IWineD3DDevice VTbl follows
7752 **********************************************************/
7754 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7756 /*** IUnknown methods ***/
7757 IWineD3DDeviceImpl_QueryInterface,
7758 IWineD3DDeviceImpl_AddRef,
7759 IWineD3DDeviceImpl_Release,
7760 /*** IWineD3DDevice methods ***/
7761 IWineD3DDeviceImpl_GetParent,
7762 /*** Creation methods**/
7763 IWineD3DDeviceImpl_CreateBuffer,
7764 IWineD3DDeviceImpl_CreateVertexBuffer,
7765 IWineD3DDeviceImpl_CreateIndexBuffer,
7766 IWineD3DDeviceImpl_CreateStateBlock,
7767 IWineD3DDeviceImpl_CreateSurface,
7768 IWineD3DDeviceImpl_CreateRendertargetView,
7769 IWineD3DDeviceImpl_CreateTexture,
7770 IWineD3DDeviceImpl_CreateVolumeTexture,
7771 IWineD3DDeviceImpl_CreateVolume,
7772 IWineD3DDeviceImpl_CreateCubeTexture,
7773 IWineD3DDeviceImpl_CreateQuery,
7774 IWineD3DDeviceImpl_CreateSwapChain,
7775 IWineD3DDeviceImpl_CreateVertexDeclaration,
7776 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7777 IWineD3DDeviceImpl_CreateVertexShader,
7778 IWineD3DDeviceImpl_CreatePixelShader,
7779 IWineD3DDeviceImpl_CreatePalette,
7780 /*** Odd functions **/
7781 IWineD3DDeviceImpl_Init3D,
7782 IWineD3DDeviceImpl_InitGDI,
7783 IWineD3DDeviceImpl_Uninit3D,
7784 IWineD3DDeviceImpl_UninitGDI,
7785 IWineD3DDeviceImpl_SetMultithreaded,
7786 IWineD3DDeviceImpl_EvictManagedResources,
7787 IWineD3DDeviceImpl_GetAvailableTextureMem,
7788 IWineD3DDeviceImpl_GetBackBuffer,
7789 IWineD3DDeviceImpl_GetCreationParameters,
7790 IWineD3DDeviceImpl_GetDeviceCaps,
7791 IWineD3DDeviceImpl_GetDirect3D,
7792 IWineD3DDeviceImpl_GetDisplayMode,
7793 IWineD3DDeviceImpl_SetDisplayMode,
7794 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7795 IWineD3DDeviceImpl_GetRasterStatus,
7796 IWineD3DDeviceImpl_GetSwapChain,
7797 IWineD3DDeviceImpl_Reset,
7798 IWineD3DDeviceImpl_SetDialogBoxMode,
7799 IWineD3DDeviceImpl_SetCursorProperties,
7800 IWineD3DDeviceImpl_SetCursorPosition,
7801 IWineD3DDeviceImpl_ShowCursor,
7802 IWineD3DDeviceImpl_TestCooperativeLevel,
7803 /*** Getters and setters **/
7804 IWineD3DDeviceImpl_SetClipPlane,
7805 IWineD3DDeviceImpl_GetClipPlane,
7806 IWineD3DDeviceImpl_SetClipStatus,
7807 IWineD3DDeviceImpl_GetClipStatus,
7808 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7809 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7810 IWineD3DDeviceImpl_SetDepthStencilSurface,
7811 IWineD3DDeviceImpl_GetDepthStencilSurface,
7812 IWineD3DDeviceImpl_SetGammaRamp,
7813 IWineD3DDeviceImpl_GetGammaRamp,
7814 IWineD3DDeviceImpl_SetIndices,
7815 IWineD3DDeviceImpl_GetIndices,
7816 IWineD3DDeviceImpl_SetBaseVertexIndex,
7817 IWineD3DDeviceImpl_GetBaseVertexIndex,
7818 IWineD3DDeviceImpl_SetLight,
7819 IWineD3DDeviceImpl_GetLight,
7820 IWineD3DDeviceImpl_SetLightEnable,
7821 IWineD3DDeviceImpl_GetLightEnable,
7822 IWineD3DDeviceImpl_SetMaterial,
7823 IWineD3DDeviceImpl_GetMaterial,
7824 IWineD3DDeviceImpl_SetNPatchMode,
7825 IWineD3DDeviceImpl_GetNPatchMode,
7826 IWineD3DDeviceImpl_SetPaletteEntries,
7827 IWineD3DDeviceImpl_GetPaletteEntries,
7828 IWineD3DDeviceImpl_SetPixelShader,
7829 IWineD3DDeviceImpl_GetPixelShader,
7830 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7831 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7832 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7833 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7834 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7835 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7836 IWineD3DDeviceImpl_SetRenderState,
7837 IWineD3DDeviceImpl_GetRenderState,
7838 IWineD3DDeviceImpl_SetRenderTarget,
7839 IWineD3DDeviceImpl_GetRenderTarget,
7840 IWineD3DDeviceImpl_SetFrontBackBuffers,
7841 IWineD3DDeviceImpl_SetSamplerState,
7842 IWineD3DDeviceImpl_GetSamplerState,
7843 IWineD3DDeviceImpl_SetScissorRect,
7844 IWineD3DDeviceImpl_GetScissorRect,
7845 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7846 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7847 IWineD3DDeviceImpl_SetStreamSource,
7848 IWineD3DDeviceImpl_GetStreamSource,
7849 IWineD3DDeviceImpl_SetStreamSourceFreq,
7850 IWineD3DDeviceImpl_GetStreamSourceFreq,
7851 IWineD3DDeviceImpl_SetTexture,
7852 IWineD3DDeviceImpl_GetTexture,
7853 IWineD3DDeviceImpl_SetTextureStageState,
7854 IWineD3DDeviceImpl_GetTextureStageState,
7855 IWineD3DDeviceImpl_SetTransform,
7856 IWineD3DDeviceImpl_GetTransform,
7857 IWineD3DDeviceImpl_SetVertexDeclaration,
7858 IWineD3DDeviceImpl_GetVertexDeclaration,
7859 IWineD3DDeviceImpl_SetVertexShader,
7860 IWineD3DDeviceImpl_GetVertexShader,
7861 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7862 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7863 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7864 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7865 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7866 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7867 IWineD3DDeviceImpl_SetViewport,
7868 IWineD3DDeviceImpl_GetViewport,
7869 IWineD3DDeviceImpl_MultiplyTransform,
7870 IWineD3DDeviceImpl_ValidateDevice,
7871 IWineD3DDeviceImpl_ProcessVertices,
7872 /*** State block ***/
7873 IWineD3DDeviceImpl_BeginStateBlock,
7874 IWineD3DDeviceImpl_EndStateBlock,
7875 /*** Scene management ***/
7876 IWineD3DDeviceImpl_BeginScene,
7877 IWineD3DDeviceImpl_EndScene,
7878 IWineD3DDeviceImpl_Present,
7879 IWineD3DDeviceImpl_Clear,
7880 IWineD3DDeviceImpl_ClearRendertargetView,
7881 /*** Drawing ***/
7882 IWineD3DDeviceImpl_SetPrimitiveType,
7883 IWineD3DDeviceImpl_GetPrimitiveType,
7884 IWineD3DDeviceImpl_DrawPrimitive,
7885 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7886 IWineD3DDeviceImpl_DrawPrimitiveUP,
7887 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7888 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7889 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7890 IWineD3DDeviceImpl_DrawRectPatch,
7891 IWineD3DDeviceImpl_DrawTriPatch,
7892 IWineD3DDeviceImpl_DeletePatch,
7893 IWineD3DDeviceImpl_ColorFill,
7894 IWineD3DDeviceImpl_UpdateTexture,
7895 IWineD3DDeviceImpl_UpdateSurface,
7896 IWineD3DDeviceImpl_GetFrontBufferData,
7897 /*** object tracking ***/
7898 IWineD3DDeviceImpl_ResourceReleased,
7899 IWineD3DDeviceImpl_EnumResources
7902 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7903 WINED3DRS_ALPHABLENDENABLE ,
7904 WINED3DRS_ALPHAFUNC ,
7905 WINED3DRS_ALPHAREF ,
7906 WINED3DRS_ALPHATESTENABLE ,
7907 WINED3DRS_BLENDOP ,
7908 WINED3DRS_COLORWRITEENABLE ,
7909 WINED3DRS_DESTBLEND ,
7910 WINED3DRS_DITHERENABLE ,
7911 WINED3DRS_FILLMODE ,
7912 WINED3DRS_FOGDENSITY ,
7913 WINED3DRS_FOGEND ,
7914 WINED3DRS_FOGSTART ,
7915 WINED3DRS_LASTPIXEL ,
7916 WINED3DRS_SHADEMODE ,
7917 WINED3DRS_SRCBLEND ,
7918 WINED3DRS_STENCILENABLE ,
7919 WINED3DRS_STENCILFAIL ,
7920 WINED3DRS_STENCILFUNC ,
7921 WINED3DRS_STENCILMASK ,
7922 WINED3DRS_STENCILPASS ,
7923 WINED3DRS_STENCILREF ,
7924 WINED3DRS_STENCILWRITEMASK ,
7925 WINED3DRS_STENCILZFAIL ,
7926 WINED3DRS_TEXTUREFACTOR ,
7927 WINED3DRS_WRAP0 ,
7928 WINED3DRS_WRAP1 ,
7929 WINED3DRS_WRAP2 ,
7930 WINED3DRS_WRAP3 ,
7931 WINED3DRS_WRAP4 ,
7932 WINED3DRS_WRAP5 ,
7933 WINED3DRS_WRAP6 ,
7934 WINED3DRS_WRAP7 ,
7935 WINED3DRS_ZENABLE ,
7936 WINED3DRS_ZFUNC ,
7937 WINED3DRS_ZWRITEENABLE
7940 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7941 WINED3DTSS_ALPHAARG0 ,
7942 WINED3DTSS_ALPHAARG1 ,
7943 WINED3DTSS_ALPHAARG2 ,
7944 WINED3DTSS_ALPHAOP ,
7945 WINED3DTSS_BUMPENVLOFFSET ,
7946 WINED3DTSS_BUMPENVLSCALE ,
7947 WINED3DTSS_BUMPENVMAT00 ,
7948 WINED3DTSS_BUMPENVMAT01 ,
7949 WINED3DTSS_BUMPENVMAT10 ,
7950 WINED3DTSS_BUMPENVMAT11 ,
7951 WINED3DTSS_COLORARG0 ,
7952 WINED3DTSS_COLORARG1 ,
7953 WINED3DTSS_COLORARG2 ,
7954 WINED3DTSS_COLOROP ,
7955 WINED3DTSS_RESULTARG ,
7956 WINED3DTSS_TEXCOORDINDEX ,
7957 WINED3DTSS_TEXTURETRANSFORMFLAGS
7960 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7961 WINED3DSAMP_ADDRESSU ,
7962 WINED3DSAMP_ADDRESSV ,
7963 WINED3DSAMP_ADDRESSW ,
7964 WINED3DSAMP_BORDERCOLOR ,
7965 WINED3DSAMP_MAGFILTER ,
7966 WINED3DSAMP_MINFILTER ,
7967 WINED3DSAMP_MIPFILTER ,
7968 WINED3DSAMP_MIPMAPLODBIAS ,
7969 WINED3DSAMP_MAXMIPLEVEL ,
7970 WINED3DSAMP_MAXANISOTROPY ,
7971 WINED3DSAMP_SRGBTEXTURE ,
7972 WINED3DSAMP_ELEMENTINDEX
7975 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7976 WINED3DRS_AMBIENT ,
7977 WINED3DRS_AMBIENTMATERIALSOURCE ,
7978 WINED3DRS_CLIPPING ,
7979 WINED3DRS_CLIPPLANEENABLE ,
7980 WINED3DRS_COLORVERTEX ,
7981 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7982 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7983 WINED3DRS_FOGDENSITY ,
7984 WINED3DRS_FOGEND ,
7985 WINED3DRS_FOGSTART ,
7986 WINED3DRS_FOGTABLEMODE ,
7987 WINED3DRS_FOGVERTEXMODE ,
7988 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7989 WINED3DRS_LIGHTING ,
7990 WINED3DRS_LOCALVIEWER ,
7991 WINED3DRS_MULTISAMPLEANTIALIAS ,
7992 WINED3DRS_MULTISAMPLEMASK ,
7993 WINED3DRS_NORMALIZENORMALS ,
7994 WINED3DRS_PATCHEDGESTYLE ,
7995 WINED3DRS_POINTSCALE_A ,
7996 WINED3DRS_POINTSCALE_B ,
7997 WINED3DRS_POINTSCALE_C ,
7998 WINED3DRS_POINTSCALEENABLE ,
7999 WINED3DRS_POINTSIZE ,
8000 WINED3DRS_POINTSIZE_MAX ,
8001 WINED3DRS_POINTSIZE_MIN ,
8002 WINED3DRS_POINTSPRITEENABLE ,
8003 WINED3DRS_RANGEFOGENABLE ,
8004 WINED3DRS_SPECULARMATERIALSOURCE ,
8005 WINED3DRS_TWEENFACTOR ,
8006 WINED3DRS_VERTEXBLEND ,
8007 WINED3DRS_CULLMODE ,
8008 WINED3DRS_FOGCOLOR
8011 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8012 WINED3DTSS_TEXCOORDINDEX ,
8013 WINED3DTSS_TEXTURETRANSFORMFLAGS
8016 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8017 WINED3DSAMP_DMAPOFFSET
8020 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8021 DWORD rep = This->StateTable[state].representative;
8022 DWORD idx;
8023 BYTE shift;
8024 UINT i;
8025 WineD3DContext *context;
8027 if(!rep) return;
8028 for(i = 0; i < This->numContexts; i++) {
8029 context = This->contexts[i];
8030 if(isStateDirty(context, rep)) continue;
8032 context->dirtyArray[context->numDirtyEntries++] = rep;
8033 idx = rep >> 5;
8034 shift = rep & 0x1f;
8035 context->isStateDirty[idx] |= (1 << shift);
8039 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8040 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8041 /* The drawable size of a pbuffer render target is the current pbuffer size
8043 *width = dev->pbufferWidth;
8044 *height = dev->pbufferHeight;
8047 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8048 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8050 *width = This->pow2Width;
8051 *height = This->pow2Height;
8054 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8055 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8056 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8057 * current context's drawable, which is the size of the back buffer of the swapchain
8058 * the active context belongs to. The back buffer of the swapchain is stored as the
8059 * surface the context belongs to.
8061 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8062 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;