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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
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:
71 case WINED3DPT_LINELIST:
74 case WINED3DPT_LINESTRIP:
77 case WINED3DPT_TRIANGLELIST:
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;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
109 return WINED3DPT_POINTLIST;
112 return WINED3DPT_LINELIST;
115 return WINED3DPT_LINESTRIP;
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;
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);
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);
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);
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);
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);
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;
226 TRACE("iface %p, desc %p, parent %p, buffer %p\n", iface, desc, parent, buffer);
228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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);
244 WARN("Failed to initialize resource, returning %#x\n", hr);
245 HeapFree(GetProcessHeap(), 0, object);
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;
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;
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));
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);
296 WARN("Failed to initialize resource, returning %#x\n", hr);
297 HeapFree(GetProcessHeap(), 0, object);
298 *ppVertexBuffer = NULL;
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;
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
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");
336 object->flags |= WINED3D_BUFFER_CREATEBO;
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);
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);
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);
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);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
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;
398 TRACE("(%p) Creating index buffer\n", This);
400 /* Allocate the storage for the device */
401 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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);
413 WARN("Failed to initialize resource, returning %#x\n", hr);
414 HeapFree(GetProcessHeap(), 0, object);
415 *ppIndexBuffer = NULL;
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;
434 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DStateBlockImpl *object;
441 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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;
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);
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 */
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);
481 memset(object->streamFreq, 1, sizeof(object->streamFreq));
483 /* Reset the ref and type after kludging it */
484 object->wineD3DDevice = This;
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++) {
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++) {
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;
697 FIXME("Unrecognized state block type %d\n", Type);
700 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
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);
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
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
727 *********************************/
728 mul_4w = (Width + 3) & ~3;
729 mul_4h = (Height + 3) & ~3;
730 if (WINED3DFMT_UNKNOWN == Format) {
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);
741 /* The pitch is a multiple of 4 bytes */
742 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
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));
752 ERR("Out of memory\n");
754 return WINED3DERR_OUTOFVIDEOMEMORY;
757 /* Look at the implementation and set the correct Vtable */
761 /* Check if a 3D adapter is available when creating gl surfaces */
764 ERR("OpenGL surfaces are not available without opengl\n");
765 HeapFree(GetProcessHeap(), 0, object);
766 return WINED3DERR_NOTAVAILABLE;
768 object->lpVtbl = &IWineD3DSurface_Vtbl;
772 object->lpVtbl = &IWineGDISurface_Vtbl;
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);
785 WARN("Failed to initialize resource, returning %#x\n", hr);
786 HeapFree(GetProcessHeap(), 0, object);
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);
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;
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 * ****************************************/
830 case WINED3DPOOL_SCRATCH:
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");
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");
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");
850 FIXME("(%p) Unknown pool %d\n", This, Pool);
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);
870 ERR("Private setup failed, returning %#x\n", hr);
871 IWineD3DSurface_Release(*ppSurface);
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));
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;
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;
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))
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)
945 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
946 return WINED3DERR_INVALIDCALL;
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;
963 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL;
971 Levels = wined3d_log2i(max(Width, Height)) + 1;
972 TRACE("Calculated levels = %d\n", Levels);
975 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
978 ERR("Out of memory\n");
980 return WINED3DERR_OUTOFVIDEOMEMORY;
983 object->lpVtbl = &IWineD3DTexture_Vtbl;
984 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, Format, Pool, parent);
987 WARN("Failed to initialize resource, returning %#x\n", hr);
988 HeapFree(GetProcessHeap(), 0, object);
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;
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;
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 */
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);
1057 object->surfaces[i] = NULL;
1058 IWineD3DTexture_Release((IWineD3DTexture *)object);
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);
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;
1088 const struct GlPixelFormatDesc *glDesc;
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;
1115 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1116 return WINED3DERR_INVALIDCALL;
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));
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);
1139 WARN("Failed to initialize resource, returning %#x\n", hr);
1140 HeapFree(GetProcessHeap(), 0, object);
1141 *ppVolumeTexture = NULL;
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;
1164 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1165 object->baseTexture.magLookup = magLookup_noFilter;
1168 /* Generate all the surfaces */
1173 for (i = 0; i < object->baseTexture.levels; i++)
1176 /* Create the volume */
1177 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1178 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1180 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1181 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1182 *ppVolumeTexture = NULL;
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);
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1203 UINT Width, UINT Height, UINT Depth,
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);
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));
1222 ERR("Out of memory\n");
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);
1232 WARN("Failed to initialize resource, returning %#x\n", hr);
1233 HeapFree(GetProcessHeap(), 0, object);
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);
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 **/
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;
1299 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1300 return WINED3DERR_INVALIDCALL;
1307 Levels = wined3d_log2i(EdgeLength) + 1;
1308 TRACE("Calculated levels = %d\n", Levels);
1311 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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);
1323 WARN("Failed to initialize resource, returning %#x\n", hr);
1324 HeapFree(GetProcessHeap(), 0, object);
1325 *ppCubeTexture = NULL;
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 */
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;
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;
1359 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1360 object->baseTexture.magLookup = magLookup_noFilter;
1363 /* Generate all the surfaces */
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]);
1382 FIXME("(%p) Failed to create surface\n",object);
1383 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1384 *ppCubeTexture = NULL;
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;
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 */
1409 case WINED3DQUERYTYPE_OCCLUSION:
1410 TRACE("(%p) occlusion query\n", This);
1411 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1414 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1416 vtable = &IWineD3DOcclusionQuery_Vtbl;
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;
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:
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) {
1451 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1454 ERR("Out of memory\n");
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;
1466 *ppQuery = (IWineD3DQuery *)object;
1468 /* allocated the 'extended' data based on the type of query requested */
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);
1479 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
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);
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");
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:
1512 object->extendedData = 0;
1513 FIXME("(%p) Unhandled query type %d\n",This , Type);
1515 TRACE("(%p) : Created Query %p\n", This, object);
1519 /*****************************************************************************
1520 * IWineD3DDeviceImpl_SetupFullscreenWindow
1522 * Helper function that modifies a HWND's Style and ExStyle for proper
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;
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;
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
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 */
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;
1638 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
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));
1663 ERR("Out of memory\n");
1664 *ppSwapChain = NULL;
1665 return WINED3DERR_OUTOFVIDEOMEMORY;
1668 switch(surface_type) {
1670 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1672 case SURFACE_OPENGL:
1673 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
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;
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);
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))) {
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);
1753 ERR("Failed to create the front buffer\n");
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");
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;
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) {
1816 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1817 if(!object->backBuffer) {
1818 ERR("Out of memory\n");
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]);
1830 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1832 ERR("Cannot create new back buffer\n");
1835 if(surface_type == SURFACE_OPENGL) {
1837 glDrawBuffer(GL_BACK);
1838 checkGLcall("glDrawBuffer(GL_BACK)");
1843 object->backBuffer = NULL;
1845 /* Single buffering - draw to front buffer */
1846 if(surface_type == SURFACE_OPENGL) {
1848 glDrawBuffer(GL_FRONT);
1849 checkGLcall("glDrawBuffer(GL_FRONT)");
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);
1866 ERR("Failed to create the auto depth stencil\n");
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);
1879 if (displaymode_set) {
1883 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
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) {
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);
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);
1941 TRACE("Swapchain out of range\n");
1943 return WINED3DERR_INVALIDCALL;
1948 * Vertex Declaration
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));
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;
1972 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1974 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1976 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1977 *ppVertexDeclaration = NULL;
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;
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));
2018 elements[size-1] = end_element;
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;
2030 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2031 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2033 elements[idx].UsageIndex = 0;
2036 if (has_blend && (num_blends > 0)) {
2037 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2038 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
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;
2046 ERR("Unexpected amount of blend values: %u\n", num_blends);
2049 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2050 elements[idx].UsageIndex = 0;
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;
2060 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2061 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2062 elements[idx].UsageIndex = 0;
2066 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2067 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2068 elements[idx].UsageIndex = 0;
2072 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2073 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2074 elements[idx].UsageIndex = 0;
2078 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2079 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2080 elements[idx].UsageIndex = 0;
2084 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2085 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2086 elements[idx].UsageIndex = 1;
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;
2095 case WINED3DFVF_TEXTUREFORMAT2:
2096 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2098 case WINED3DFVF_TEXTUREFORMAT3:
2099 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2101 case WINED3DFVF_TEXTUREFORMAT4:
2102 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2105 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2106 elements[idx].UsageIndex = idx2;
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;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2123 WINED3DVERTEXELEMENT* elements = NULL;
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
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;
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));
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);
2168 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2169 IWineD3DVertexShader_Release(*ppVertexShader);
2170 *ppVertexShader = NULL;
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));
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);
2203 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2204 IWineD3DPixelShader_Release(*ppPixelShader);
2205 *ppPixelShader = NULL;
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;
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));
2223 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2224 return E_OUTOFMEMORY;
2227 object->lpVtbl = &IWineD3DPalette_Vtbl;
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));
2236 HeapFree( GetProcessHeap(), 0, object);
2237 return E_OUTOFMEMORY;
2240 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2242 IWineD3DPalette_Release((IWineD3DPalette *) object);
2246 *Palette = (IWineD3DPalette *) object;
2251 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2255 HDC dcb = NULL, dcs = NULL;
2256 WINEDDCOLORKEY colorkey;
2258 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2261 GetObjectA(hbm, sizeof(BITMAP), &bm);
2262 dcb = CreateCompatibleDC(NULL);
2264 SelectObject(dcb, hbm);
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));
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);
2280 ERR("Wine logo requested, but failed to create surface\n");
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);
2294 /* Fill the surface with a white color to show that wined3d is there */
2295 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2308 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
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 */
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)");
2351 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2352 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2355 IWineD3DSwapChainImpl *swapchain = NULL;
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,
2371 (IWineD3DStateBlock **)&This->stateBlock,
2373 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2374 WARN("Failed to create stateblock\n");
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");
2390 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2391 if(!This->palettes[0]) {
2392 ERR("Out of memory!\n");
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;
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);
2420 WARN("Failed to create implicit swapchain\n");
2424 This->NumberOfSwapChains = 1;
2425 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2426 if(!This->swapchains) {
2427 ERR("Out of memory!\n");
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];
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);
2454 TRACE("Shader private data couldn't be allocated\n");
2457 hr = This->frag_pipe->alloc_private(iface);
2459 TRACE("Fragment pipeline private data couldn't be allocated\n");
2462 hr = This->blitter->alloc_private(iface);
2464 TRACE("Blitter private data couldn't be allocated\n");
2468 /* Set up some starting GL setup */
2470 /* Setup all the devices defaults */
2471 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2472 create_dummy_textures(This);
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) {
2485 This->offscreenBuffer = GL_BACK;
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;
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);
2503 /* Clear the screen */
2504 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2505 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 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;
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;
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);
2546 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2547 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2550 IWineD3DSwapChainImpl *swapchain = NULL;
2553 /* Setup the implicit swapchain */
2554 TRACE("Creating implicit swapchain\n");
2555 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2556 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2559 WARN("Failed to create implicit swapchain\n");
2563 This->NumberOfSwapChains = 1;
2564 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2565 if(!This->swapchains) {
2566 ERR("Out of memory!\n");
2569 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2573 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2577 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
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) {
2605 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
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) {
2616 glDeleteTextures(1, &This->cursorTexture);
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;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
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;
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;
2745 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2746 const WINED3DDISPLAYMODE* pMode) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
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) ) {
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);
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);
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);
2825 * Get / Set Stream Source
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");
2853 This->updateStateBlock->streamSource[StreamNumber] = 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);
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);
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];
2898 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2901 if (*pStream != NULL) {
2902 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
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;
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);
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);
2952 * Get / Set & Multiply Transform
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;
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");
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));
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];
3008 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3009 const WINED3DMATRIX *mat = NULL;
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];
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);
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) {
3044 PLIGHTINFOEL *object = NULL;
3045 UINT Hi = LIGHTMAP_HASHFUNC(Index);
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
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
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;
3073 case WINED3DLIGHT_DIRECTIONAL:
3074 /* Ignores attenuation */
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;
3089 TRACE("Adding new light\n");
3090 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*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:
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;
3124 case WINED3DLIGHT_DIRECTIONAL:
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;
3134 case WINED3DLIGHT_SPOT:
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;
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;
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;
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));
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);
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;
3198 if (lightInfo == NULL) {
3199 TRACE("Light information requested but light not defined\n");
3200 return WINED3DERR_INVALIDCALL;
3203 *pLight = lightInfo->OriginalParms;
3208 * Get / Set Light Enable
3209 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
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);
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;
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;
3240 if (lightInfo == NULL) {
3241 FIXME("Adding default lights has failed dismally\n");
3242 return WINED3DERR_INVALIDCALL;
3246 lightInfo->enabledChanged = TRUE;
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;
3256 TRACE("Light already disabled, nothing to do\n");
3258 lightInfo->enabled = FALSE;
3260 lightInfo->enabled = TRUE;
3261 if (lightInfo->glIndex != -1) {
3263 TRACE("Nothing to do as light was enabled\n");
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;
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");
3286 /* i == lightInfo->glIndex */
3287 if(!This->isRecordingState) {
3288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3296 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3298 PLIGHTINFOEL *lightInfo = NULL;
3299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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;
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;
3320 * Get / Set Clip Planes
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");
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");
3353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
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];
3376 * Get / Set Clip Plane Status
3377 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
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;
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;
3402 * Get / Set Material
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");
3416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
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);
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);
3457 if(oldIdxs != pIndexData) {
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3459 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3460 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
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 */
3472 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3473 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3475 TRACE("(%p) No index data set\n", This);
3477 TRACE("Returning %p\n", *ppIndexData);
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");
3492 This->updateStateBlock->baseVertexIndex = BaseIndex;
3494 if (This->isRecordingState) {
3495 TRACE("Recording... not performing anything\n");
3498 /* The base vertex index affects the stream sources */
3499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
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);
3515 * Get / Set Viewports
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");
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);
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;
3546 * Get / Set Render States
3547 * TODO: Verify against dx9 definitions
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");
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");
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
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];
3583 * Get / Set Sampler States
3584 * TODO: Verify against dx9 definitions
3587 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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
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(...).
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");
3627 if(oldValue == Value) {
3628 TRACE("Application is setting the old value over, nothing to do\n");
3632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
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);
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");
3665 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3667 if(This->isRecordingState) {
3668 TRACE("Recording... not performing anything\n");
3672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
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);
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");
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");
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
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);
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");
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");
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);
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);
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3759 IWineD3DDevice *iface,
3761 CONST BOOL *srcData,
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);
3786 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3787 IWineD3DDevice *iface,
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));
3805 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3806 IWineD3DDevice *iface,
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);
3834 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3835 IWineD3DDevice *iface,
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);
3853 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3854 IWineD3DDevice *iface,
3856 CONST float *srcData,
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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);
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);
3888 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3889 IWineD3DDevice *iface,
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);
3907 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
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) {
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 */
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) {
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);
3986 /* Now work out the mapping */
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);
4002 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4003 const DWORD *sampler_tokens =
4004 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
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 */
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;
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] != -1) {
4063 /* Already mapped somewhere */
4067 while (start >= 0) {
4068 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4069 device_map_stage(This, vsampler_idx, start);
4070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4082 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4083 BOOL vs = use_vs(This->stateBlock);
4084 BOOL ps = use_ps(This->stateBlock);
4087 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4088 * that would be really messy and require shader recompilation
4089 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4090 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4093 device_map_psamplers(This);
4095 device_map_fixed_function_samplers(This);
4099 device_map_vsamplers(This, ps);
4103 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4105 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4106 This->updateStateBlock->pixelShader = pShader;
4107 This->updateStateBlock->changed.pixelShader = TRUE;
4109 /* Handle recording of state blocks */
4110 if (This->isRecordingState) {
4111 TRACE("Recording... not performing anything\n");
4114 if (This->isRecordingState) {
4115 TRACE("Recording... not performing anything\n");
4116 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4117 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4121 if(pShader == oldShader) {
4122 TRACE("App is setting the old pixel shader over, nothing to do\n");
4126 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4127 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4129 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4135 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 if (NULL == ppShader) {
4139 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4140 return WINED3DERR_INVALIDCALL;
4143 *ppShader = This->stateBlock->pixelShader;
4144 if (NULL != *ppShader) {
4145 IWineD3DPixelShader_AddRef(*ppShader);
4147 TRACE("(%p) : returning %p\n", This, *ppShader);
4151 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4152 IWineD3DDevice *iface,
4154 CONST BOOL *srcData,
4157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4158 int i, cnt = min(count, MAX_CONST_B - start);
4160 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4161 iface, srcData, start, count);
4163 if (srcData == NULL || cnt < 0)
4164 return WINED3DERR_INVALIDCALL;
4166 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4167 for (i = 0; i < cnt; i++)
4168 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4170 for (i = start; i < cnt + start; ++i) {
4171 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4174 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4179 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4180 IWineD3DDevice *iface,
4185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4186 int cnt = min(count, MAX_CONST_B - start);
4188 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4189 iface, dstData, start, count);
4191 if (dstData == NULL || cnt < 0)
4192 return WINED3DERR_INVALIDCALL;
4194 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4198 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4199 IWineD3DDevice *iface,
4204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4205 int i, cnt = min(count, MAX_CONST_I - start);
4207 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4208 iface, srcData, start, count);
4210 if (srcData == NULL || cnt < 0)
4211 return WINED3DERR_INVALIDCALL;
4213 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4214 for (i = 0; i < cnt; i++)
4215 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4216 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4218 for (i = start; i < cnt + start; ++i) {
4219 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4222 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4227 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4228 IWineD3DDevice *iface,
4233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4234 int cnt = min(count, MAX_CONST_I - start);
4236 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4237 iface, dstData, start, count);
4239 if (dstData == NULL || cnt < 0)
4240 return WINED3DERR_INVALIDCALL;
4242 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4246 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4247 IWineD3DDevice *iface,
4249 CONST float *srcData,
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4255 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4256 iface, srcData, start, count);
4258 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4259 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4260 return WINED3DERR_INVALIDCALL;
4262 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4264 for (i = 0; i < count; i++)
4265 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4266 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4269 if (!This->isRecordingState)
4271 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4275 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4276 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4281 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4282 IWineD3DDevice *iface,
4287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4290 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4291 iface, dstData, start, count);
4293 if (dstData == NULL || cnt < 0)
4294 return WINED3DERR_INVALIDCALL;
4296 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4300 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4301 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4302 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4304 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4306 DWORD DestFVF = dest->fvf;
4308 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4312 if (lpStrideData->u.s.normal.lpData) {
4313 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4316 if (lpStrideData->u.s.position.lpData == NULL) {
4317 ERR("Source has no position mask\n");
4318 return WINED3DERR_INVALIDCALL;
4321 /* We might access VBOs from this code, so hold the lock */
4324 if (dest->resource.allocatedMemory == NULL) {
4325 /* This may happen if we do direct locking into a vbo. Unlikely,
4326 * but theoretically possible(ddraw processvertices test)
4328 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4329 if(!dest->resource.allocatedMemory) {
4331 ERR("Out of memory\n");
4332 return E_OUTOFMEMORY;
4334 if (dest->buffer_object)
4337 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4338 checkGLcall("glBindBufferARB");
4339 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4341 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4343 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4344 checkGLcall("glUnmapBufferARB");
4348 /* Get a pointer into the destination vbo(create one if none exists) and
4349 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4351 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4353 dest->flags |= WINED3D_BUFFER_CREATEBO;
4354 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4357 if (dest->buffer_object)
4359 unsigned char extrabytes = 0;
4360 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4361 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4362 * this may write 4 extra bytes beyond the area that should be written
4364 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4365 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4366 if(!dest_conv_addr) {
4367 ERR("Out of memory\n");
4368 /* Continue without storing converted vertices */
4370 dest_conv = dest_conv_addr;
4374 * a) WINED3DRS_CLIPPING is enabled
4375 * b) WINED3DVOP_CLIP is passed
4377 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4378 static BOOL warned = FALSE;
4380 * The clipping code is not quite correct. Some things need
4381 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4382 * so disable clipping for now.
4383 * (The graphics in Half-Life are broken, and my processvertices
4384 * test crashes with IDirect3DDevice3)
4390 FIXME("Clipping is broken and disabled for now\n");
4392 } else doClip = FALSE;
4393 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4395 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4398 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4399 WINED3DTS_PROJECTION,
4401 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4402 WINED3DTS_WORLDMATRIX(0),
4405 TRACE("View mat:\n");
4406 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);
4407 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);
4408 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);
4409 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);
4411 TRACE("Proj mat:\n");
4412 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);
4413 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);
4414 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);
4415 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);
4417 TRACE("World mat:\n");
4418 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);
4419 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);
4420 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);
4421 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);
4423 /* Get the viewport */
4424 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4425 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4426 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4428 multiply_matrix(&mat,&view_mat,&world_mat);
4429 multiply_matrix(&mat,&proj_mat,&mat);
4431 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4433 for (i = 0; i < dwCount; i+= 1) {
4434 unsigned int tex_index;
4436 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4437 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4438 /* The position first */
4440 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4442 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4444 /* Multiplication with world, view and projection matrix */
4445 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);
4446 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);
4447 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);
4448 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);
4450 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4452 /* WARNING: The following things are taken from d3d7 and were not yet checked
4453 * against d3d8 or d3d9!
4456 /* Clipping conditions: From msdn
4458 * A vertex is clipped if it does not match the following requirements
4462 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4464 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4465 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4470 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4471 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4474 /* "Normal" viewport transformation (not clipped)
4475 * 1) The values are divided by rhw
4476 * 2) The y axis is negative, so multiply it with -1
4477 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4478 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4479 * 4) Multiply x with Width/2 and add Width/2
4480 * 5) The same for the height
4481 * 6) Add the viewpoint X and Y to the 2D coordinates and
4482 * The minimum Z value to z
4483 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4485 * Well, basically it's simply a linear transformation into viewport
4497 z *= vp.MaxZ - vp.MinZ;
4499 x += vp.Width / 2 + vp.X;
4500 y += vp.Height / 2 + vp.Y;
4505 /* That vertex got clipped
4506 * Contrary to OpenGL it is not dropped completely, it just
4507 * undergoes a different calculation.
4509 TRACE("Vertex got clipped\n");
4516 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4517 * outside of the main vertex buffer memory. That needs some more
4522 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4525 ( (float *) dest_ptr)[0] = x;
4526 ( (float *) dest_ptr)[1] = y;
4527 ( (float *) dest_ptr)[2] = z;
4528 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4530 dest_ptr += 3 * sizeof(float);
4532 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4533 dest_ptr += sizeof(float);
4538 ( (float *) dest_conv)[0] = x * w;
4539 ( (float *) dest_conv)[1] = y * w;
4540 ( (float *) dest_conv)[2] = z * w;
4541 ( (float *) dest_conv)[3] = w;
4543 dest_conv += 3 * sizeof(float);
4545 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4546 dest_conv += sizeof(float);
4550 if (DestFVF & WINED3DFVF_PSIZE) {
4551 dest_ptr += sizeof(DWORD);
4552 if(dest_conv) dest_conv += sizeof(DWORD);
4554 if (DestFVF & WINED3DFVF_NORMAL) {
4555 const float *normal =
4556 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4557 /* AFAIK this should go into the lighting information */
4558 FIXME("Didn't expect the destination to have a normal\n");
4559 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4561 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4565 if (DestFVF & WINED3DFVF_DIFFUSE) {
4566 const DWORD *color_d =
4567 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4569 static BOOL warned = FALSE;
4572 ERR("No diffuse color in source, but destination has one\n");
4576 *( (DWORD *) dest_ptr) = 0xffffffff;
4577 dest_ptr += sizeof(DWORD);
4580 *( (DWORD *) dest_conv) = 0xffffffff;
4581 dest_conv += sizeof(DWORD);
4585 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4587 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4588 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4589 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4590 dest_conv += sizeof(DWORD);
4595 if (DestFVF & WINED3DFVF_SPECULAR) {
4596 /* What's the color value in the feedback buffer? */
4597 const DWORD *color_s =
4598 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4600 static BOOL warned = FALSE;
4603 ERR("No specular color in source, but destination has one\n");
4607 *( (DWORD *) dest_ptr) = 0xFF000000;
4608 dest_ptr += sizeof(DWORD);
4611 *( (DWORD *) dest_conv) = 0xFF000000;
4612 dest_conv += sizeof(DWORD);
4616 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4618 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4619 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4620 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4621 dest_conv += sizeof(DWORD);
4626 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4627 const float *tex_coord =
4628 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4629 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4631 ERR("No source texture, but destination requests one\n");
4632 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4633 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4636 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4638 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4645 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4646 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4647 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4648 dwCount * get_flexible_vertex_size(DestFVF),
4650 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4651 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4658 #undef copy_and_next
4660 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4661 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 WineDirect3DVertexStridedData strided;
4665 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4666 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4669 ERR("Output vertex declaration not implemented yet\n");
4672 /* Need any context to write to the vbo. */
4673 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4675 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4676 * control the streamIsUP flag, thus restore it afterwards.
4678 This->stateBlock->streamIsUP = FALSE;
4679 memset(&strided, 0, sizeof(strided));
4680 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4681 This->stateBlock->streamIsUP = streamWasUP;
4683 if(vbo || SrcStartIndex) {
4685 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4686 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4688 * Also get the start index in, but only loop over all elements if there's something to add at all.
4690 #define FIXSRC(type) \
4691 if(strided.u.s.type.VBO) { \
4692 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4693 strided.u.s.type.VBO = 0; \
4694 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4696 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4697 vb->buffer_object = 0; \
4700 if(strided.u.s.type.lpData) { \
4701 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4704 FIXSRC(blendWeights);
4705 FIXSRC(blendMatrixIndices);
4710 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4711 FIXSRC(texCoords[i]);
4724 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4725 (struct wined3d_buffer *)pDestBuffer, Flags);
4729 * Get / Set Texture Stage States
4730 * TODO: Verify against dx9 definitions
4732 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4734 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4736 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4738 if (Stage >= MAX_TEXTURES) {
4739 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4743 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4744 This->updateStateBlock->textureState[Stage][Type] = Value;
4746 if (This->isRecordingState) {
4747 TRACE("Recording... not performing anything\n");
4751 /* Checked after the assignments to allow proper stateblock recording */
4752 if(oldValue == Value) {
4753 TRACE("App is setting the old value over, nothing to do\n");
4757 if(Stage > This->stateBlock->lowest_disabled_stage &&
4758 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4759 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4760 * Changes in other states are important on disabled stages too
4765 if(Type == WINED3DTSS_COLOROP) {
4768 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4769 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4770 * they have to be disabled
4772 * The current stage is dirtified below.
4774 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4775 TRACE("Additionally dirtifying stage %d\n", i);
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4778 This->stateBlock->lowest_disabled_stage = Stage;
4779 TRACE("New lowest disabled: %d\n", Stage);
4780 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4781 /* Previously disabled stage enabled. Stages above it may need enabling
4782 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4783 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4785 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4788 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4789 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4792 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4795 This->stateBlock->lowest_disabled_stage = i;
4796 TRACE("New lowest disabled: %d\n", i);
4800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4805 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4808 *pValue = This->updateStateBlock->textureState[Stage][Type];
4815 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4817 IWineD3DBaseTexture *oldTexture;
4819 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4821 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4822 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4825 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4826 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4827 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4830 oldTexture = This->updateStateBlock->textures[Stage];
4832 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4833 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4835 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4836 return WINED3DERR_INVALIDCALL;
4839 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4840 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4842 This->updateStateBlock->changed.textures |= 1 << Stage;
4843 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4844 This->updateStateBlock->textures[Stage] = pTexture;
4846 /* Handle recording of state blocks */
4847 if (This->isRecordingState) {
4848 TRACE("Recording... not performing anything\n");
4852 if(oldTexture == pTexture) {
4853 TRACE("App is setting the same texture again, nothing to do\n");
4857 /** NOTE: MSDN says that setTexture increases the reference count,
4858 * and that the application must set the texture back to null (or have a leaky application),
4859 * This means we should pass the refcount up to the parent
4860 *******************************/
4861 if (NULL != This->updateStateBlock->textures[Stage]) {
4862 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4863 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4864 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4866 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4868 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4873 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4874 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4875 * so the COLOROP and ALPHAOP have to be dirtified.
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4880 if(bindCount == 1) {
4881 new->baseTexture.sampler = Stage;
4883 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4887 if (NULL != oldTexture) {
4888 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4889 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4891 IWineD3DBaseTexture_Release(oldTexture);
4892 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4897 if(bindCount && old->baseTexture.sampler == Stage) {
4899 /* Have to do a search for the other sampler(s) where the texture is bound to
4900 * Shouldn't happen as long as apps bind a texture only to one stage
4902 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4903 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4904 if(This->updateStateBlock->textures[i] == oldTexture) {
4905 old->baseTexture.sampler = i;
4912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4917 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4920 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4922 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4923 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4926 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4927 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4928 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4931 *ppTexture=This->stateBlock->textures[Stage];
4933 IWineD3DBaseTexture_AddRef(*ppTexture);
4935 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4943 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4944 IWineD3DSurface **ppBackBuffer) {
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 IWineD3DSwapChain *swapChain;
4949 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4951 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4952 if (hr == WINED3D_OK) {
4953 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4954 IWineD3DSwapChain_Release(swapChain);
4956 *ppBackBuffer = NULL;
4961 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 WARN("(%p) : stub, calling idirect3d for now\n", This);
4964 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4967 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4969 IWineD3DSwapChain *swapChain;
4972 if(iSwapChain > 0) {
4973 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4974 if (hr == WINED3D_OK) {
4975 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4976 IWineD3DSwapChain_Release(swapChain);
4978 FIXME("(%p) Error getting display mode\n", This);
4981 /* Don't read the real display mode,
4982 but return the stored mode instead. X11 can't change the color
4983 depth, and some apps are pretty angry if they SetDisplayMode from
4984 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4986 Also don't relay to the swapchain because with ddraw it's possible
4987 that there isn't a swapchain at all */
4988 pMode->Width = This->ddraw_width;
4989 pMode->Height = This->ddraw_height;
4990 pMode->Format = This->ddraw_format;
4991 pMode->RefreshRate = 0;
4999 * Stateblock related functions
5002 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5004 IWineD3DStateBlock *stateblock;
5007 TRACE("(%p)\n", This);
5009 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5011 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5012 if (FAILED(hr)) return hr;
5014 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5015 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5016 This->isRecordingState = TRUE;
5018 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5023 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5026 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5028 if (!This->isRecordingState) {
5029 WARN("(%p) not recording! returning error\n", This);
5030 *ppStateBlock = NULL;
5031 return WINED3DERR_INVALIDCALL;
5034 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5036 DWORD map = object->changed.renderState[i];
5037 for (j = 0; map; map >>= 1, ++j)
5039 if (!(map & 1)) continue;
5041 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5045 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5047 DWORD map = object->changed.transform[i];
5048 for (j = 0; map; map >>= 1, ++j)
5050 if (!(map & 1)) continue;
5052 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5055 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5056 if(object->changed.vertexShaderConstantsF[i]) {
5057 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5058 object->num_contained_vs_consts_f++;
5061 for(i = 0; i < MAX_CONST_I; i++) {
5062 if (object->changed.vertexShaderConstantsI & (1 << i))
5064 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5065 object->num_contained_vs_consts_i++;
5068 for(i = 0; i < MAX_CONST_B; i++) {
5069 if (object->changed.vertexShaderConstantsB & (1 << i))
5071 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5072 object->num_contained_vs_consts_b++;
5075 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5077 if (object->changed.pixelShaderConstantsF[i])
5079 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5080 ++object->num_contained_ps_consts_f;
5083 for(i = 0; i < MAX_CONST_I; i++) {
5084 if (object->changed.pixelShaderConstantsI & (1 << i))
5086 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5087 object->num_contained_ps_consts_i++;
5090 for(i = 0; i < MAX_CONST_B; i++) {
5091 if (object->changed.pixelShaderConstantsB & (1 << i))
5093 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5094 object->num_contained_ps_consts_b++;
5097 for(i = 0; i < MAX_TEXTURES; i++) {
5098 DWORD map = object->changed.textureState[i];
5100 for(j = 0; map; map >>= 1, ++j)
5102 if (!(map & 1)) continue;
5104 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5105 object->contained_tss_states[object->num_contained_tss_states].state = j;
5106 ++object->num_contained_tss_states;
5109 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5110 DWORD map = object->changed.samplerState[i];
5112 for (j = 0; map; map >>= 1, ++j)
5114 if (!(map & 1)) continue;
5116 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5117 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5118 ++object->num_contained_sampler_states;
5122 *ppStateBlock = (IWineD3DStateBlock*) object;
5123 This->isRecordingState = FALSE;
5124 This->updateStateBlock = This->stateBlock;
5125 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5126 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5127 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5132 * Scene related functions
5134 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5135 /* At the moment we have no need for any functionality at the beginning
5137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 TRACE("(%p)\n", This);
5141 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5142 return WINED3DERR_INVALIDCALL;
5144 This->inScene = TRUE;
5148 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5150 TRACE("(%p)\n", This);
5152 if(!This->inScene) {
5153 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5154 return WINED3DERR_INVALIDCALL;
5157 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5158 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5160 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5164 This->inScene = FALSE;
5168 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5169 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5170 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5172 IWineD3DSwapChain *swapChain = NULL;
5174 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5176 TRACE("(%p) Presenting the frame\n", This);
5178 for(i = 0 ; i < swapchains ; i ++) {
5180 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5181 TRACE("presentinng chain %d, %p\n", i, swapChain);
5182 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5183 IWineD3DSwapChain_Release(swapChain);
5189 /* Not called from the VTable (internal subroutine) */
5190 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5191 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5192 float Z, DWORD Stencil) {
5193 GLbitfield glMask = 0;
5195 WINED3DRECT curRect;
5197 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5198 UINT drawable_width, drawable_height;
5199 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5200 IWineD3DSwapChainImpl *swapchain = NULL;
5202 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5203 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5204 * for the cleared parts, and the untouched parts.
5206 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5207 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5208 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5209 * checking all this if the dest surface is in the drawable anyway.
5211 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5213 if(vp->X != 0 || vp->Y != 0 ||
5214 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5215 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5218 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5219 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5220 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5221 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5222 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5225 if(Count > 0 && pRects && (
5226 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5227 pRects[0].x2 < target->currentDesc.Width ||
5228 pRects[0].y2 < target->currentDesc.Height)) {
5229 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5236 target->get_drawable_size(target, &drawable_width, &drawable_height);
5238 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5241 /* Only set the values up once, as they are not changing */
5242 if (Flags & WINED3DCLEAR_STENCIL) {
5243 glClearStencil(Stencil);
5244 checkGLcall("glClearStencil");
5245 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5246 glStencilMask(0xFFFFFFFF);
5249 if (Flags & WINED3DCLEAR_ZBUFFER) {
5250 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5251 glDepthMask(GL_TRUE);
5253 checkGLcall("glClearDepth");
5254 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5257 if (vp->X != 0 || vp->Y != 0 ||
5258 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5259 surface_load_ds_location(This->stencilBufferTarget, location);
5261 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5262 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5263 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5264 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5265 surface_load_ds_location(This->stencilBufferTarget, location);
5267 else if (Count > 0 && pRects && (
5268 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5269 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5270 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5271 surface_load_ds_location(This->stencilBufferTarget, location);
5275 if (Flags & WINED3DCLEAR_TARGET) {
5276 TRACE("Clearing screen with glClear to color %x\n", Color);
5277 glClearColor(D3DCOLOR_R(Color),
5281 checkGLcall("glClearColor");
5283 /* Clear ALL colors! */
5284 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5285 glMask = glMask | GL_COLOR_BUFFER_BIT;
5288 vp_rect.left = vp->X;
5289 vp_rect.top = vp->Y;
5290 vp_rect.right = vp->X + vp->Width;
5291 vp_rect.bottom = vp->Y + vp->Height;
5292 if (!(Count > 0 && pRects)) {
5293 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5294 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5296 if(This->render_offscreen) {
5297 glScissor(vp_rect.left, vp_rect.top,
5298 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5300 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5301 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5303 checkGLcall("glScissor");
5305 checkGLcall("glClear");
5307 /* Now process each rect in turn */
5308 for (i = 0; i < Count; i++) {
5309 /* Note gl uses lower left, width/height */
5310 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5311 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5312 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5314 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5315 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5316 curRect.x1, (target->currentDesc.Height - curRect.y2),
5317 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5319 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5320 * The rectangle is not cleared, no error is returned, but further rectanlges are
5321 * still cleared if they are valid
5323 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5324 TRACE("Rectangle with negative dimensions, ignoring\n");
5328 if(This->render_offscreen) {
5329 glScissor(curRect.x1, curRect.y1,
5330 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5332 glScissor(curRect.x1, drawable_height - curRect.y2,
5333 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5335 checkGLcall("glScissor");
5338 checkGLcall("glClear");
5342 /* Restore the old values (why..?) */
5343 if (Flags & WINED3DCLEAR_STENCIL) {
5344 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5346 if (Flags & WINED3DCLEAR_TARGET) {
5347 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5348 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5349 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5350 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5351 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5353 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5354 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5356 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5358 if (Flags & WINED3DCLEAR_ZBUFFER) {
5359 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5360 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5361 surface_modify_ds_location(This->stencilBufferTarget, location);
5366 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5367 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5370 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5376 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5377 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5379 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5381 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5382 Count, pRects, Flags, Color, Z, Stencil);
5384 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5385 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5386 /* TODO: What about depth stencil buffers without stencil bits? */
5387 return WINED3DERR_INVALIDCALL;
5390 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5397 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5398 WINED3DPRIMITIVETYPE primitive_type)
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5402 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5404 This->updateStateBlock->changed.primitive_type = TRUE;
5405 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5408 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5409 WINED3DPRIMITIVETYPE *primitive_type)
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5415 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5417 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5420 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5424 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5426 if(!This->stateBlock->vertexDecl) {
5427 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5428 return WINED3DERR_INVALIDCALL;
5431 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5432 if(This->stateBlock->streamIsUP) {
5433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5434 This->stateBlock->streamIsUP = FALSE;
5437 if(This->stateBlock->loadBaseVertexIndex != 0) {
5438 This->stateBlock->loadBaseVertexIndex = 0;
5439 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5441 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5442 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5443 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5447 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5448 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5452 IWineD3DIndexBuffer *pIB;
5453 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5456 pIB = This->stateBlock->pIndexData;
5458 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5459 * without an index buffer set. (The first time at least...)
5460 * D3D8 simply dies, but I doubt it can do much harm to return
5461 * D3DERR_INVALIDCALL there as well. */
5462 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5463 return WINED3DERR_INVALIDCALL;
5466 if(!This->stateBlock->vertexDecl) {
5467 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5468 return WINED3DERR_INVALIDCALL;
5471 if(This->stateBlock->streamIsUP) {
5472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5473 This->stateBlock->streamIsUP = FALSE;
5475 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5477 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5478 This, minIndex, NumVertices, startIndex, index_count);
5480 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5481 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5487 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5488 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5492 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5493 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5498 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5499 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5504 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5505 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5507 if(!This->stateBlock->vertexDecl) {
5508 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5509 return WINED3DERR_INVALIDCALL;
5512 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5513 vb = This->stateBlock->streamSource[0];
5514 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5515 if (vb) IWineD3DBuffer_Release(vb);
5516 This->stateBlock->streamOffset[0] = 0;
5517 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5518 This->stateBlock->streamIsUP = TRUE;
5519 This->stateBlock->loadBaseVertexIndex = 0;
5521 /* TODO: Only mark dirty if drawing from a different UP address */
5522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5524 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5525 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5527 /* MSDN specifies stream zero settings must be set to NULL */
5528 This->stateBlock->streamStride[0] = 0;
5529 This->stateBlock->streamSource[0] = NULL;
5531 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5532 * the new stream sources or use UP drawing again
5537 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5538 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5539 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5544 IWineD3DIndexBuffer *ib;
5546 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5547 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5548 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5550 if(!This->stateBlock->vertexDecl) {
5551 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5552 return WINED3DERR_INVALIDCALL;
5555 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5561 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5562 vb = This->stateBlock->streamSource[0];
5563 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5564 if (vb) IWineD3DBuffer_Release(vb);
5565 This->stateBlock->streamIsUP = TRUE;
5566 This->stateBlock->streamOffset[0] = 0;
5567 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5569 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5570 This->stateBlock->baseVertexIndex = 0;
5571 This->stateBlock->loadBaseVertexIndex = 0;
5572 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5576 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5577 idxStride, pIndexData, MinVertexIndex);
5579 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5580 This->stateBlock->streamSource[0] = NULL;
5581 This->stateBlock->streamStride[0] = 0;
5582 ib = This->stateBlock->pIndexData;
5584 IWineD3DIndexBuffer_Release(ib);
5585 This->stateBlock->pIndexData = NULL;
5587 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5588 * SetStreamSource to specify a vertex buffer
5594 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5595 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5599 /* Mark the state dirty until we have nicer tracking
5600 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5605 This->stateBlock->baseVertexIndex = 0;
5606 This->up_strided = DrawPrimStrideData;
5607 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5608 This->up_strided = NULL;
5612 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5613 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5614 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5617 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5619 /* Mark the state dirty until we have nicer tracking
5620 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5625 This->stateBlock->streamIsUP = TRUE;
5626 This->stateBlock->baseVertexIndex = 0;
5627 This->up_strided = DrawPrimStrideData;
5628 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5629 This->up_strided = NULL;
5633 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5634 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5635 * not callable by the app directly no parameter validation checks are needed here.
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5638 WINED3DLOCKED_BOX src;
5639 WINED3DLOCKED_BOX dst;
5641 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5643 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5644 * dirtification to improve loading performance.
5646 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5647 if(FAILED(hr)) return hr;
5648 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5650 IWineD3DVolume_UnlockBox(pSourceVolume);
5654 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5656 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5658 IWineD3DVolume_UnlockBox(pSourceVolume);
5660 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5665 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5666 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 HRESULT hr = WINED3D_OK;
5669 WINED3DRESOURCETYPE sourceType;
5670 WINED3DRESOURCETYPE destinationType;
5673 /* TODO: think about moving the code into IWineD3DBaseTexture */
5675 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5677 /* verify that the source and destination textures aren't NULL */
5678 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5679 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5680 This, pSourceTexture, pDestinationTexture);
5681 hr = WINED3DERR_INVALIDCALL;
5684 if (pSourceTexture == pDestinationTexture) {
5685 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5686 This, pSourceTexture, pDestinationTexture);
5687 hr = WINED3DERR_INVALIDCALL;
5689 /* Verify that the source and destination textures are the same type */
5690 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5691 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5693 if (sourceType != destinationType) {
5694 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5696 hr = WINED3DERR_INVALIDCALL;
5699 /* check that both textures have the identical numbers of levels */
5700 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5701 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5702 hr = WINED3DERR_INVALIDCALL;
5705 if (WINED3D_OK == hr) {
5706 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5708 /* Make sure that the destination texture is loaded */
5709 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5711 /* Update every surface level of the texture */
5712 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5714 switch (sourceType) {
5715 case WINED3DRTYPE_TEXTURE:
5717 IWineD3DSurface *srcSurface;
5718 IWineD3DSurface *destSurface;
5720 for (i = 0 ; i < levels ; ++i) {
5721 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5722 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5723 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5724 IWineD3DSurface_Release(srcSurface);
5725 IWineD3DSurface_Release(destSurface);
5726 if (WINED3D_OK != hr) {
5727 WARN("(%p) : Call to update surface failed\n", This);
5733 case WINED3DRTYPE_CUBETEXTURE:
5735 IWineD3DSurface *srcSurface;
5736 IWineD3DSurface *destSurface;
5737 WINED3DCUBEMAP_FACES faceType;
5739 for (i = 0 ; i < levels ; ++i) {
5740 /* Update each cube face */
5741 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5742 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5743 if (WINED3D_OK != hr) {
5744 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5746 TRACE("Got srcSurface %p\n", srcSurface);
5748 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5749 if (WINED3D_OK != hr) {
5750 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5752 TRACE("Got desrSurface %p\n", destSurface);
5754 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5755 IWineD3DSurface_Release(srcSurface);
5756 IWineD3DSurface_Release(destSurface);
5757 if (WINED3D_OK != hr) {
5758 WARN("(%p) : Call to update surface failed\n", This);
5766 case WINED3DRTYPE_VOLUMETEXTURE:
5768 IWineD3DVolume *srcVolume = NULL;
5769 IWineD3DVolume *destVolume = NULL;
5771 for (i = 0 ; i < levels ; ++i) {
5772 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5773 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5774 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5775 IWineD3DVolume_Release(srcVolume);
5776 IWineD3DVolume_Release(destVolume);
5777 if (WINED3D_OK != hr) {
5778 WARN("(%p) : Call to update volume failed\n", This);
5786 FIXME("(%p) : Unsupported source and destination type\n", This);
5787 hr = WINED3DERR_INVALIDCALL;
5794 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5795 IWineD3DSwapChain *swapChain;
5797 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5798 if(hr == WINED3D_OK) {
5799 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5800 IWineD3DSwapChain_Release(swapChain);
5805 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5807 IWineD3DBaseTextureImpl *texture;
5808 const struct GlPixelFormatDesc *gl_info;
5811 TRACE("(%p) : %p\n", This, pNumPasses);
5813 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5814 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5815 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5816 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5818 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5819 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5820 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5823 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5824 if(!texture) continue;
5825 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5826 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5828 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5829 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5832 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5833 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5836 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5837 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5838 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5843 /* return a sensible default */
5846 TRACE("returning D3D_OK\n");
5850 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5854 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5855 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5856 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5857 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5862 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5866 PALETTEENTRY **palettes;
5868 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5870 if (PaletteNumber >= MAX_PALETTES) {
5871 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5872 return WINED3DERR_INVALIDCALL;
5875 if (PaletteNumber >= This->NumberOfPalettes) {
5876 NewSize = This->NumberOfPalettes;
5879 } while(PaletteNumber >= NewSize);
5880 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5882 ERR("Out of memory!\n");
5883 return E_OUTOFMEMORY;
5885 This->palettes = palettes;
5886 This->NumberOfPalettes = NewSize;
5889 if (!This->palettes[PaletteNumber]) {
5890 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5891 if (!This->palettes[PaletteNumber]) {
5892 ERR("Out of memory!\n");
5893 return E_OUTOFMEMORY;
5897 for (j = 0; j < 256; ++j) {
5898 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5899 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5900 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5901 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5903 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5904 TRACE("(%p) : returning\n", This);
5908 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5911 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5912 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5913 /* What happens in such situation isn't documented; Native seems to silently abort
5914 on such conditions. Return Invalid Call. */
5915 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5916 return WINED3DERR_INVALIDCALL;
5918 for (j = 0; j < 256; ++j) {
5919 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5920 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5921 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5922 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5924 TRACE("(%p) : returning\n", This);
5928 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5931 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5932 (tested with reference rasterizer). Return Invalid Call. */
5933 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5934 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5935 return WINED3DERR_INVALIDCALL;
5937 /*TODO: stateblocks */
5938 if (This->currentPalette != PaletteNumber) {
5939 This->currentPalette = PaletteNumber;
5940 dirtify_p8_texture_samplers(This);
5942 TRACE("(%p) : returning\n", This);
5946 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5948 if (PaletteNumber == NULL) {
5949 WARN("(%p) : returning Invalid Call\n", This);
5950 return WINED3DERR_INVALIDCALL;
5952 /*TODO: stateblocks */
5953 *PaletteNumber = This->currentPalette;
5954 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5958 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5963 FIXME("(%p) : stub\n", This);
5967 This->softwareVertexProcessing = bSoftware;
5972 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5977 FIXME("(%p) : stub\n", This);
5980 return This->softwareVertexProcessing;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 IWineD3DSwapChain *swapChain;
5989 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5991 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5992 if(hr == WINED3D_OK){
5993 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5994 IWineD3DSwapChain_Release(swapChain);
5996 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6002 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6005 if(nSegments != 0.0f) {
6008 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6015 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6020 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6026 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6028 /** TODO: remove casts to IWineD3DSurfaceImpl
6029 * NOTE: move code to surface to accomplish this
6030 ****************************************/
6031 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6032 int srcWidth, srcHeight;
6033 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6034 WINED3DFORMAT destFormat, srcFormat;
6036 int srcLeft, destLeft, destTop;
6037 WINED3DPOOL srcPool, destPool;
6039 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6040 glDescriptor *glDescription = NULL;
6044 CONVERT_TYPES convert = NO_CONVERSION;
6046 WINED3DSURFACE_DESC winedesc;
6048 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6049 memset(&winedesc, 0, sizeof(winedesc));
6050 winedesc.Width = &srcSurfaceWidth;
6051 winedesc.Height = &srcSurfaceHeight;
6052 winedesc.Pool = &srcPool;
6053 winedesc.Format = &srcFormat;
6055 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6057 winedesc.Width = &destSurfaceWidth;
6058 winedesc.Height = &destSurfaceHeight;
6059 winedesc.Pool = &destPool;
6060 winedesc.Format = &destFormat;
6061 winedesc.Size = &destSize;
6063 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6065 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6066 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6067 return WINED3DERR_INVALIDCALL;
6070 /* This call loads the opengl surface directly, instead of copying the surface to the
6071 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6072 * copy in sysmem and use regular surface loading.
6074 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6075 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6076 if(convert != NO_CONVERSION) {
6077 return IWineD3DSurface_BltFast(pDestinationSurface,
6078 pDestPoint ? pDestPoint->x : 0,
6079 pDestPoint ? pDestPoint->y : 0,
6080 pSourceSurface, pSourceRect, 0);
6083 if (destFormat == WINED3DFMT_UNKNOWN) {
6084 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6085 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6087 /* Get the update surface description */
6088 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6091 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6094 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6095 checkGLcall("glActiveTextureARB");
6098 /* Make sure the surface is loaded and up to date */
6099 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6100 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6102 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6104 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6105 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6106 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6107 srcLeft = pSourceRect ? pSourceRect->left : 0;
6108 destLeft = pDestPoint ? pDestPoint->x : 0;
6109 destTop = pDestPoint ? pDestPoint->y : 0;
6112 /* This function doesn't support compressed textures
6113 the pitch is just bytesPerPixel * width */
6114 if(srcWidth != srcSurfaceWidth || srcLeft ){
6115 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6116 offset += srcLeft * pSrcSurface->bytesPerPixel;
6117 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6119 /* TODO DXT formats */
6121 if(pSourceRect != NULL && pSourceRect->top != 0){
6122 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
6124 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6125 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
6126 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6129 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6131 /* need to lock the surface to get the data */
6132 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6137 /* TODO: Cube and volume support */
6139 /* not a whole row so we have to do it a line at a time */
6142 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6143 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6145 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6147 glTexSubImage2D(glDescription->target
6148 ,glDescription->level
6153 ,glDescription->glFormat
6154 ,glDescription->glType
6155 ,data /* could be quicker using */
6160 } else { /* Full width, so just write out the whole texture */
6161 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6163 if (WINED3DFMT_DXT1 == destFormat ||
6164 WINED3DFMT_DXT2 == destFormat ||
6165 WINED3DFMT_DXT3 == destFormat ||
6166 WINED3DFMT_DXT4 == destFormat ||
6167 WINED3DFMT_DXT5 == destFormat) {
6168 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6169 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6170 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6171 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6172 } if (destFormat != srcFormat) {
6173 FIXME("Updating mixed format compressed texture is not curretly support\n");
6175 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6176 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6179 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6184 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6185 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6188 checkGLcall("glTexSubImage2D");
6192 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6193 sampler = This->rev_tex_unit_map[0];
6194 if (sampler != -1) {
6195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6201 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6203 struct WineD3DRectPatch *patch;
6204 GLenum old_primitive_type;
6208 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6210 if(!(Handle || pRectPatchInfo)) {
6211 /* TODO: Write a test for the return value, thus the FIXME */
6212 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6213 return WINED3DERR_INVALIDCALL;
6217 i = PATCHMAP_HASHFUNC(Handle);
6219 LIST_FOR_EACH(e, &This->patches[i]) {
6220 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6221 if(patch->Handle == Handle) {
6228 TRACE("Patch does not exist. Creating a new one\n");
6229 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6230 patch->Handle = Handle;
6231 list_add_head(&This->patches[i], &patch->entry);
6233 TRACE("Found existing patch %p\n", patch);
6236 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6237 * attributes we have to tesselate, read back, and draw. This needs a patch
6238 * management structure instance. Create one.
6240 * A possible improvement is to check if a vertex shader is used, and if not directly
6243 FIXME("Drawing an uncached patch. This is slow\n");
6244 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6247 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6248 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6249 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6251 TRACE("Tesselation density or patch info changed, retesselating\n");
6253 if(pRectPatchInfo) {
6254 patch->RectPatchInfo = *pRectPatchInfo;
6256 patch->numSegs[0] = pNumSegs[0];
6257 patch->numSegs[1] = pNumSegs[1];
6258 patch->numSegs[2] = pNumSegs[2];
6259 patch->numSegs[3] = pNumSegs[3];
6261 hr = tesselate_rectpatch(This, patch);
6263 WARN("Patch tesselation failed\n");
6265 /* Do not release the handle to store the params of the patch */
6267 HeapFree(GetProcessHeap(), 0, patch);
6273 This->currentPatch = patch;
6274 old_primitive_type = This->stateBlock->gl_primitive_type;
6275 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6276 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6277 This->stateBlock->gl_primitive_type = old_primitive_type;
6278 This->currentPatch = NULL;
6280 /* Destroy uncached patches */
6282 HeapFree(GetProcessHeap(), 0, patch->mem);
6283 HeapFree(GetProcessHeap(), 0, patch);
6288 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6290 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6291 FIXME("(%p) : Stub\n", This);
6295 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 struct WineD3DRectPatch *patch;
6300 TRACE("(%p) Handle(%d)\n", This, Handle);
6302 i = PATCHMAP_HASHFUNC(Handle);
6303 LIST_FOR_EACH(e, &This->patches[i]) {
6304 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6305 if(patch->Handle == Handle) {
6306 TRACE("Deleting patch %p\n", patch);
6307 list_remove(&patch->entry);
6308 HeapFree(GetProcessHeap(), 0, patch->mem);
6309 HeapFree(GetProcessHeap(), 0, patch);
6314 /* TODO: Write a test for the return value */
6315 FIXME("Attempt to destroy nonexistent patch\n");
6316 return WINED3DERR_INVALIDCALL;
6319 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6321 IWineD3DSwapChain *swapchain;
6323 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6324 if (SUCCEEDED(hr)) {
6325 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6332 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6333 const WINED3DRECT *rect, const float color[4])
6335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6336 IWineD3DSwapChain *swapchain;
6338 swapchain = get_swapchain(surface);
6342 TRACE("Surface %p is onscreen\n", surface);
6344 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6346 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6347 buffer = surface_get_gl_buffer(surface, swapchain);
6348 glDrawBuffer(buffer);
6349 checkGLcall("glDrawBuffer()");
6351 TRACE("Surface %p is offscreen\n", surface);
6353 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6355 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6356 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6357 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6358 checkGLcall("glFramebufferRenderbufferEXT");
6362 glEnable(GL_SCISSOR_TEST);
6364 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6366 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6367 rect->x2 - rect->x1, rect->y2 - rect->y1);
6369 checkGLcall("glScissor");
6370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6372 glDisable(GL_SCISSOR_TEST);
6374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6376 glDisable(GL_BLEND);
6377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6379 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6382 glClearColor(color[0], color[1], color[2], color[3]);
6383 glClear(GL_COLOR_BUFFER_BIT);
6384 checkGLcall("glClear");
6386 if (This->activeContext->current_fbo) {
6387 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6389 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6390 checkGLcall("glBindFramebuffer()");
6393 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6394 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6395 glDrawBuffer(GL_BACK);
6396 checkGLcall("glDrawBuffer()");
6402 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6403 unsigned int r, g, b, a;
6406 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6407 destfmt == WINED3DFMT_R8G8B8)
6410 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6412 a = (color & 0xff000000) >> 24;
6413 r = (color & 0x00ff0000) >> 16;
6414 g = (color & 0x0000ff00) >> 8;
6415 b = (color & 0x000000ff) >> 0;
6419 case WINED3DFMT_R5G6B5:
6420 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6427 TRACE("Returning %08x\n", ret);
6430 case WINED3DFMT_X1R5G5B5:
6431 case WINED3DFMT_A1R5G5B5:
6440 TRACE("Returning %08x\n", ret);
6443 case WINED3DFMT_A8_UNORM:
6444 TRACE("Returning %08x\n", a);
6447 case WINED3DFMT_X4R4G4B4:
6448 case WINED3DFMT_A4R4G4B4:
6457 TRACE("Returning %08x\n", ret);
6460 case WINED3DFMT_R3G3B2:
6467 TRACE("Returning %08x\n", ret);
6470 case WINED3DFMT_X8B8G8R8:
6471 case WINED3DFMT_R8G8B8A8_UNORM:
6476 TRACE("Returning %08x\n", ret);
6479 case WINED3DFMT_A2R10G10B10:
6481 r = (r * 1024) / 256;
6482 g = (g * 1024) / 256;
6483 b = (b * 1024) / 256;
6488 TRACE("Returning %08x\n", ret);
6491 case WINED3DFMT_R10G10B10A2_UNORM:
6493 r = (r * 1024) / 256;
6494 g = (g * 1024) / 256;
6495 b = (b * 1024) / 256;
6500 TRACE("Returning %08x\n", ret);
6504 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6509 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6511 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6513 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6515 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6516 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6517 return WINED3DERR_INVALIDCALL;
6520 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6521 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6522 color_fill_fbo(iface, pSurface, pRect, c);
6525 /* Just forward this to the DirectDraw blitting engine */
6526 memset(&BltFx, 0, sizeof(BltFx));
6527 BltFx.dwSize = sizeof(BltFx);
6528 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6529 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6530 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6534 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6535 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6537 IWineD3DResource *resource;
6538 IWineD3DSurface *surface;
6541 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6544 ERR("Failed to get resource, hr %#x\n", hr);
6548 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6550 FIXME("Only supported on surface resources\n");
6551 IWineD3DResource_Release(resource);
6555 surface = (IWineD3DSurface *)resource;
6557 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6559 color_fill_fbo(iface, surface, NULL, color);
6566 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6568 c = ((DWORD)(color[2] * 255.0));
6569 c |= ((DWORD)(color[1] * 255.0)) << 8;
6570 c |= ((DWORD)(color[0] * 255.0)) << 16;
6571 c |= ((DWORD)(color[3] * 255.0)) << 24;
6573 /* Just forward this to the DirectDraw blitting engine */
6574 memset(&BltFx, 0, sizeof(BltFx));
6575 BltFx.dwSize = sizeof(BltFx);
6576 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format);
6577 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6580 ERR("Blt failed, hr %#x\n", hr);
6584 IWineD3DResource_Release(resource);
6587 /* rendertarget and depth stencil functions */
6588 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6591 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6592 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6593 return WINED3DERR_INVALIDCALL;
6596 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6597 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6598 /* Note inc ref on returned surface */
6599 if(*ppRenderTarget != NULL)
6600 IWineD3DSurface_AddRef(*ppRenderTarget);
6604 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6606 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6607 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6608 IWineD3DSwapChainImpl *Swapchain;
6611 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6613 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6614 if(hr != WINED3D_OK) {
6615 ERR("Can't get the swapchain\n");
6619 /* Make sure to release the swapchain */
6620 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6622 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6623 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6624 return WINED3DERR_INVALIDCALL;
6626 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6627 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6628 return WINED3DERR_INVALIDCALL;
6631 if(Swapchain->frontBuffer != Front) {
6632 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6634 if(Swapchain->frontBuffer)
6635 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6636 Swapchain->frontBuffer = Front;
6638 if(Swapchain->frontBuffer) {
6639 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6643 if(Back && !Swapchain->backBuffer) {
6644 /* We need memory for the back buffer array - only one back buffer this way */
6645 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6646 if(!Swapchain->backBuffer) {
6647 ERR("Out of memory\n");
6648 return E_OUTOFMEMORY;
6652 if(Swapchain->backBuffer[0] != Back) {
6653 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6655 /* What to do about the context here in the case of multithreading? Not sure.
6656 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6659 if(!Swapchain->backBuffer[0]) {
6660 /* GL was told to draw to the front buffer at creation,
6663 glDrawBuffer(GL_BACK);
6664 checkGLcall("glDrawBuffer(GL_BACK)");
6665 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6666 Swapchain->presentParms.BackBufferCount = 1;
6668 /* That makes problems - disable for now */
6669 /* glDrawBuffer(GL_FRONT); */
6670 checkGLcall("glDrawBuffer(GL_FRONT)");
6671 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6672 Swapchain->presentParms.BackBufferCount = 0;
6676 if(Swapchain->backBuffer[0])
6677 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6678 Swapchain->backBuffer[0] = Back;
6680 if(Swapchain->backBuffer[0]) {
6681 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6683 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6684 Swapchain->backBuffer = NULL;
6692 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6694 *ppZStencilSurface = This->stencilBufferTarget;
6695 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6697 if(*ppZStencilSurface != NULL) {
6698 /* Note inc ref on returned surface */
6699 IWineD3DSurface_AddRef(*ppZStencilSurface);
6702 return WINED3DERR_NOTFOUND;
6706 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6707 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6710 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6711 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6713 POINT offset = {0, 0};
6715 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6716 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6717 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6718 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6721 case WINED3DTEXF_LINEAR:
6722 gl_filter = GL_LINEAR;
6726 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6727 case WINED3DTEXF_NONE:
6728 case WINED3DTEXF_POINT:
6729 gl_filter = GL_NEAREST;
6733 /* Attach src surface to src fbo */
6734 src_swapchain = get_swapchain(src_surface);
6735 if (src_swapchain) {
6736 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6738 TRACE("Source surface %p is onscreen\n", src_surface);
6739 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6740 /* Make sure the drawable is up to date. In the offscreen case
6741 * attach_surface_fbo() implicitly takes care of this. */
6742 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6744 if(buffer == GL_FRONT) {
6747 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6748 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6749 h = windowsize.bottom - windowsize.top;
6750 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6751 src_rect->y1 = offset.y + h - src_rect->y1;
6752 src_rect->y2 = offset.y + h - src_rect->y2;
6754 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6755 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6759 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6760 glReadBuffer(buffer);
6761 checkGLcall("glReadBuffer()");
6763 TRACE("Source surface %p is offscreen\n", src_surface);
6765 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6766 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6767 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6768 checkGLcall("glReadBuffer()");
6769 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6770 checkGLcall("glFramebufferRenderbufferEXT");
6774 /* Attach dst surface to dst fbo */
6775 dst_swapchain = get_swapchain(dst_surface);
6776 if (dst_swapchain) {
6777 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6779 TRACE("Destination surface %p is onscreen\n", dst_surface);
6780 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6781 /* Make sure the drawable is up to date. In the offscreen case
6782 * attach_surface_fbo() implicitly takes care of this. */
6783 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6785 if(buffer == GL_FRONT) {
6788 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6789 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6790 h = windowsize.bottom - windowsize.top;
6791 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6792 dst_rect->y1 = offset.y + h - dst_rect->y1;
6793 dst_rect->y2 = offset.y + h - dst_rect->y2;
6795 /* Screen coords = window coords, surface height = window height */
6796 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6797 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6801 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6802 glDrawBuffer(buffer);
6803 checkGLcall("glDrawBuffer()");
6805 TRACE("Destination surface %p is offscreen\n", dst_surface);
6807 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6808 if(!src_swapchain) {
6809 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6813 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6814 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6815 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6816 checkGLcall("glDrawBuffer()");
6817 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6818 checkGLcall("glFramebufferRenderbufferEXT");
6820 glDisable(GL_SCISSOR_TEST);
6821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6824 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6825 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6826 checkGLcall("glBlitFramebuffer()");
6828 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6829 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6830 checkGLcall("glBlitFramebuffer()");
6833 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6835 if (This->activeContext->current_fbo) {
6836 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6838 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6839 checkGLcall("glBindFramebuffer()");
6842 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6843 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6844 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6845 glDrawBuffer(GL_BACK);
6846 checkGLcall("glDrawBuffer()");
6851 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6853 WINED3DVIEWPORT viewport;
6855 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6857 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6858 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6859 This, RenderTargetIndex, GL_LIMITS(buffers));
6860 return WINED3DERR_INVALIDCALL;
6863 /* MSDN says that null disables the render target
6864 but a device must always be associated with a render target
6865 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6867 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6868 FIXME("Trying to set render target 0 to NULL\n");
6869 return WINED3DERR_INVALIDCALL;
6871 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6872 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);
6873 return WINED3DERR_INVALIDCALL;
6876 /* If we are trying to set what we already have, don't bother */
6877 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6878 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6881 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6882 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6883 This->render_targets[RenderTargetIndex] = pRenderTarget;
6885 /* Render target 0 is special */
6886 if(RenderTargetIndex == 0) {
6887 /* Finally, reset the viewport as the MSDN states. */
6888 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6889 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6892 viewport.MaxZ = 1.0f;
6893 viewport.MinZ = 0.0f;
6894 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6895 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6896 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6903 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6905 HRESULT hr = WINED3D_OK;
6906 IWineD3DSurface *tmp;
6908 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6910 if (pNewZStencil == This->stencilBufferTarget) {
6911 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6913 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6914 * depending on the renter target implementation being used.
6915 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6916 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6917 * stencil buffer and incur an extra memory overhead
6918 ******************************************************/
6920 if (This->stencilBufferTarget) {
6921 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6922 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6923 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6925 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6926 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6927 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6931 tmp = This->stencilBufferTarget;
6932 This->stencilBufferTarget = pNewZStencil;
6933 /* should we be calling the parent or the wined3d surface? */
6934 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6935 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6938 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6939 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6949 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6950 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6952 /* TODO: the use of Impl is deprecated. */
6953 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6954 WINED3DLOCKED_RECT lockedRect;
6956 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6958 /* some basic validation checks */
6959 if(This->cursorTexture) {
6960 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6962 glDeleteTextures(1, &This->cursorTexture);
6964 This->cursorTexture = 0;
6967 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6968 This->haveHardwareCursor = TRUE;
6970 This->haveHardwareCursor = FALSE;
6973 WINED3DLOCKED_RECT rect;
6975 /* MSDN: Cursor must be A8R8G8B8 */
6976 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6977 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6978 return WINED3DERR_INVALIDCALL;
6981 /* MSDN: Cursor must be smaller than the display mode */
6982 if(pSur->currentDesc.Width > This->ddraw_width ||
6983 pSur->currentDesc.Height > This->ddraw_height) {
6984 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);
6985 return WINED3DERR_INVALIDCALL;
6988 if (!This->haveHardwareCursor) {
6989 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6991 /* Do not store the surface's pointer because the application may
6992 * release it after setting the cursor image. Windows doesn't
6993 * addref the set surface, so we can't do this either without
6994 * creating circular refcount dependencies. Copy out the gl texture
6997 This->cursorWidth = pSur->currentDesc.Width;
6998 This->cursorHeight = pSur->currentDesc.Height;
6999 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7001 const struct GlPixelFormatDesc *glDesc;
7002 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
7003 char *mem, *bits = rect.pBits;
7004 GLint intfmt = glDesc->glInternal;
7005 GLint format = glDesc->glFormat;
7006 GLint type = glDesc->glType;
7007 INT height = This->cursorHeight;
7008 INT width = This->cursorWidth;
7009 INT bpp = tableEntry->bpp;
7012 /* Reformat the texture memory (pitch and width can be
7014 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7015 for(i = 0; i < height; i++)
7016 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7017 IWineD3DSurface_UnlockRect(pCursorBitmap);
7020 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7021 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7022 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7025 /* Make sure that a proper texture unit is selected */
7026 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7027 checkGLcall("glActiveTextureARB");
7028 sampler = This->rev_tex_unit_map[0];
7029 if (sampler != -1) {
7030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7032 /* Create a new cursor texture */
7033 glGenTextures(1, &This->cursorTexture);
7034 checkGLcall("glGenTextures");
7035 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7036 checkGLcall("glBindTexture");
7037 /* Copy the bitmap memory into the cursor texture */
7038 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7039 HeapFree(GetProcessHeap(), 0, mem);
7040 checkGLcall("glTexImage2D");
7042 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7051 FIXME("A cursor texture was not returned.\n");
7052 This->cursorTexture = 0;
7057 /* Draw a hardware cursor */
7058 ICONINFO cursorInfo;
7060 /* Create and clear maskBits because it is not needed for
7061 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7063 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7064 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7065 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7066 WINED3DLOCK_NO_DIRTY_UPDATE |
7067 WINED3DLOCK_READONLY
7069 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7070 pSur->currentDesc.Height);
7072 cursorInfo.fIcon = FALSE;
7073 cursorInfo.xHotspot = XHotSpot;
7074 cursorInfo.yHotspot = YHotSpot;
7075 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7076 pSur->currentDesc.Height, 1,
7078 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7079 pSur->currentDesc.Height, 1,
7080 32, lockedRect.pBits);
7081 IWineD3DSurface_UnlockRect(pCursorBitmap);
7082 /* Create our cursor and clean up. */
7083 cursor = CreateIconIndirect(&cursorInfo);
7085 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7086 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7087 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7088 This->hardwareCursor = cursor;
7089 HeapFree(GetProcessHeap(), 0, maskBits);
7093 This->xHotSpot = XHotSpot;
7094 This->yHotSpot = YHotSpot;
7098 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7100 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7102 This->xScreenSpace = XScreenSpace;
7103 This->yScreenSpace = YScreenSpace;
7109 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7111 BOOL oldVisible = This->bCursorVisible;
7114 TRACE("(%p) : visible(%d)\n", This, bShow);
7117 * When ShowCursor is first called it should make the cursor appear at the OS's last
7118 * known cursor position. Because of this, some applications just repetitively call
7119 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7122 This->xScreenSpace = pt.x;
7123 This->yScreenSpace = pt.y;
7125 if (This->haveHardwareCursor) {
7126 This->bCursorVisible = bShow;
7128 SetCursor(This->hardwareCursor);
7134 if (This->cursorTexture)
7135 This->bCursorVisible = bShow;
7141 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7143 IWineD3DResourceImpl *resource;
7144 TRACE("(%p) : state (%u)\n", This, This->state);
7146 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7147 switch (This->state) {
7150 case WINED3DERR_DEVICELOST:
7152 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7153 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7154 return WINED3DERR_DEVICENOTRESET;
7156 return WINED3DERR_DEVICELOST;
7158 case WINED3DERR_DRIVERINTERNALERROR:
7159 return WINED3DERR_DRIVERINTERNALERROR;
7163 return WINED3DERR_DRIVERINTERNALERROR;
7167 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7169 /** FIXME: Resource tracking needs to be done,
7170 * The closes we can do to this is set the priorities of all managed textures low
7171 * and then reset them.
7172 ***********************************************************/
7173 FIXME("(%p) : stub\n", This);
7177 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7179 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7181 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7182 if(surface->Flags & SFLAG_DIBSECTION) {
7183 /* Release the DC */
7184 SelectObject(surface->hDC, surface->dib.holdbitmap);
7185 DeleteDC(surface->hDC);
7186 /* Release the DIB section */
7187 DeleteObject(surface->dib.DIBsection);
7188 surface->dib.bitmap_data = NULL;
7189 surface->resource.allocatedMemory = NULL;
7190 surface->Flags &= ~SFLAG_DIBSECTION;
7192 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7193 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7194 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7195 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7196 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7197 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7199 surface->pow2Width = surface->pow2Height = 1;
7200 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7201 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7203 surface->glRect.left = 0;
7204 surface->glRect.top = 0;
7205 surface->glRect.right = surface->pow2Width;
7206 surface->glRect.bottom = surface->pow2Height;
7208 if(surface->glDescription.textureName) {
7209 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7211 glDeleteTextures(1, &surface->glDescription.textureName);
7213 surface->glDescription.textureName = 0;
7214 surface->Flags &= ~SFLAG_CLIENT;
7216 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7217 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7218 surface->Flags |= SFLAG_NONPOW2;
7220 surface->Flags &= ~SFLAG_NONPOW2;
7222 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7223 surface->resource.allocatedMemory = NULL;
7224 surface->resource.heapMemory = NULL;
7225 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7226 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7227 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7228 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7230 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7234 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7235 TRACE("Unloading resource %p\n", resource);
7236 IWineD3DResource_UnLoad(resource);
7237 IWineD3DResource_Release(resource);
7241 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7244 WINED3DDISPLAYMODE m;
7247 /* All Windowed modes are supported, as is leaving the current mode */
7248 if(pp->Windowed) return TRUE;
7249 if(!pp->BackBufferWidth) return TRUE;
7250 if(!pp->BackBufferHeight) return TRUE;
7252 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7253 for(i = 0; i < count; i++) {
7254 memset(&m, 0, sizeof(m));
7255 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7257 ERR("EnumAdapterModes failed\n");
7259 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7260 /* Mode found, it is supported */
7264 /* Mode not found -> not supported */
7268 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7270 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7272 IWineD3DBaseShaderImpl *shader;
7274 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7275 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7276 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7280 if(This->depth_blt_texture) {
7281 glDeleteTextures(1, &This->depth_blt_texture);
7282 This->depth_blt_texture = 0;
7284 if (This->depth_blt_rb) {
7285 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7286 This->depth_blt_rb = 0;
7287 This->depth_blt_rb_w = 0;
7288 This->depth_blt_rb_h = 0;
7292 This->blitter->free_private(iface);
7293 This->frag_pipe->free_private(iface);
7294 This->shader_backend->shader_free_private(iface);
7297 for (i = 0; i < GL_LIMITS(textures); i++) {
7298 /* Textures are recreated below */
7299 glDeleteTextures(1, &This->dummyTextureName[i]);
7300 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7301 This->dummyTextureName[i] = 0;
7305 while(This->numContexts) {
7306 DestroyContext(This, This->contexts[0]);
7308 This->activeContext = NULL;
7309 HeapFree(GetProcessHeap(), 0, swapchain->context);
7310 swapchain->context = NULL;
7311 swapchain->num_contexts = 0;
7314 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7316 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7318 IWineD3DSurfaceImpl *target;
7320 /* Recreate the primary swapchain's context */
7321 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7322 if(swapchain->backBuffer) {
7323 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7325 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7327 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7328 &swapchain->presentParms);
7329 swapchain->num_contexts = 1;
7330 This->activeContext = swapchain->context[0];
7332 create_dummy_textures(This);
7334 hr = This->shader_backend->shader_alloc_private(iface);
7336 ERR("Failed to recreate shader private data\n");
7339 hr = This->frag_pipe->alloc_private(iface);
7341 TRACE("Fragment pipeline private data couldn't be allocated\n");
7344 hr = This->blitter->alloc_private(iface);
7346 TRACE("Blitter private data couldn't be allocated\n");
7353 This->blitter->free_private(iface);
7354 This->frag_pipe->free_private(iface);
7355 This->shader_backend->shader_free_private(iface);
7359 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7361 IWineD3DSwapChainImpl *swapchain;
7363 BOOL DisplayModeChanged = FALSE;
7364 WINED3DDISPLAYMODE mode;
7365 TRACE("(%p)\n", This);
7367 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7369 ERR("Failed to get the first implicit swapchain\n");
7373 if(!is_display_mode_supported(This, pPresentationParameters)) {
7374 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7375 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7376 pPresentationParameters->BackBufferHeight);
7377 return WINED3DERR_INVALIDCALL;
7380 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7381 * on an existing gl context, so there's no real need for recreation.
7383 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7385 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7387 TRACE("New params:\n");
7388 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7389 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7390 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7391 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7392 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7393 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7394 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7395 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7396 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7397 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7398 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7399 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7400 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7402 /* No special treatment of these parameters. Just store them */
7403 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7404 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7405 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7406 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7408 /* What to do about these? */
7409 if(pPresentationParameters->BackBufferCount != 0 &&
7410 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7411 ERR("Cannot change the back buffer count yet\n");
7413 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7414 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7415 ERR("Cannot change the back buffer format yet\n");
7417 if(pPresentationParameters->hDeviceWindow != NULL &&
7418 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7419 ERR("Cannot change the device window yet\n");
7421 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7422 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7423 return WINED3DERR_INVALIDCALL;
7426 /* Reset the depth stencil */
7427 if (pPresentationParameters->EnableAutoDepthStencil)
7428 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7430 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7432 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7434 if(pPresentationParameters->Windowed) {
7435 mode.Width = swapchain->orig_width;
7436 mode.Height = swapchain->orig_height;
7437 mode.RefreshRate = 0;
7438 mode.Format = swapchain->presentParms.BackBufferFormat;
7440 mode.Width = pPresentationParameters->BackBufferWidth;
7441 mode.Height = pPresentationParameters->BackBufferHeight;
7442 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7443 mode.Format = swapchain->presentParms.BackBufferFormat;
7446 /* Should Width == 800 && Height == 0 set 800x600? */
7447 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7448 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7449 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7453 if(!pPresentationParameters->Windowed) {
7454 DisplayModeChanged = TRUE;
7456 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7457 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7459 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7460 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7461 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7463 if(This->auto_depth_stencil_buffer) {
7464 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7468 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7469 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7470 DisplayModeChanged) {
7472 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7474 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7475 if(swapchain->presentParms.Windowed) {
7476 /* switch from windowed to fs */
7477 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7478 pPresentationParameters->BackBufferWidth,
7479 pPresentationParameters->BackBufferHeight);
7481 /* Fullscreen -> fullscreen mode change */
7482 MoveWindow(swapchain->win_handle, 0, 0,
7483 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7486 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7487 /* Fullscreen -> windowed switch */
7488 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7490 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7491 } else if(!pPresentationParameters->Windowed) {
7492 DWORD style = This->style, exStyle = This->exStyle;
7493 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7494 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7495 * Reset to clear up their mess. Guild Wars also loses the device during that.
7499 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7500 pPresentationParameters->BackBufferWidth,
7501 pPresentationParameters->BackBufferHeight);
7502 This->style = style;
7503 This->exStyle = exStyle;
7506 TRACE("Resetting stateblock\n");
7507 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7508 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7510 /* Note: No parent needed for initial internal stateblock */
7511 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7512 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7513 else TRACE("Created stateblock %p\n", This->stateBlock);
7514 This->updateStateBlock = This->stateBlock;
7515 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7517 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7519 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7522 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7523 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7525 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7531 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7533 /** FIXME: always true at the moment **/
7534 if(!bEnableDialogs) {
7535 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7541 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7543 TRACE("(%p) : pParameters %p\n", This, pParameters);
7545 *pParameters = This->createParms;
7549 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7550 IWineD3DSwapChain *swapchain;
7552 TRACE("Relaying to swapchain\n");
7554 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7555 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7556 IWineD3DSwapChain_Release(swapchain);
7561 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7562 IWineD3DSwapChain *swapchain;
7564 TRACE("Relaying to swapchain\n");
7566 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7567 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7568 IWineD3DSwapChain_Release(swapchain);
7574 /** ********************************************************
7575 * Notification functions
7576 ** ********************************************************/
7577 /** This function must be called in the release of a resource when ref == 0,
7578 * the contents of resource must still be correct,
7579 * any handles to other resource held by the caller must be closed
7580 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7581 *****************************************************/
7582 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7585 TRACE("(%p) : Adding Resource %p\n", This, resource);
7586 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7589 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7592 TRACE("(%p) : Removing resource %p\n", This, resource);
7594 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7598 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7600 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7603 TRACE("(%p) : resource %p\n", This, resource);
7605 context_resource_released(iface, resource, type);
7608 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7609 case WINED3DRTYPE_SURFACE: {
7612 /* Cleanup any FBO attachments if d3d is enabled */
7613 if(This->d3d_initialized) {
7614 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7615 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7617 TRACE("Last active render target destroyed\n");
7618 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7619 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7620 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7621 * and the lastActiveRenderTarget member shouldn't matter
7624 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7625 TRACE("Activating primary back buffer\n");
7626 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7627 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7628 /* Single buffering environment */
7629 TRACE("Activating primary front buffer\n");
7630 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7632 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7633 /* Implicit render target destroyed, that means the device is being destroyed
7634 * whatever we set here, it shouldn't matter
7636 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7639 /* May happen during ddraw uninitialization */
7640 TRACE("Render target set, but swapchain does not exist!\n");
7641 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7645 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7646 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7647 This->render_targets[i] = NULL;
7650 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7651 This->stencilBufferTarget = NULL;
7657 case WINED3DRTYPE_TEXTURE:
7658 case WINED3DRTYPE_CUBETEXTURE:
7659 case WINED3DRTYPE_VOLUMETEXTURE:
7660 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7661 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7662 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7663 This->stateBlock->textures[counter] = NULL;
7665 if (This->updateStateBlock != This->stateBlock ){
7666 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7667 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7668 This->updateStateBlock->textures[counter] = NULL;
7673 case WINED3DRTYPE_VOLUME:
7674 /* TODO: nothing really? */
7676 case WINED3DRTYPE_VERTEXBUFFER:
7679 TRACE("Cleaning up stream pointers\n");
7681 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7682 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7683 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7685 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7686 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7687 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7688 This->updateStateBlock->streamSource[streamNumber] = 0;
7689 /* Set changed flag? */
7692 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) */
7693 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7694 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7695 This->stateBlock->streamSource[streamNumber] = 0;
7701 case WINED3DRTYPE_INDEXBUFFER:
7702 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7703 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7704 This->updateStateBlock->pIndexData = NULL;
7707 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7708 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7709 This->stateBlock->pIndexData = NULL;
7714 case WINED3DRTYPE_BUFFER:
7715 /* Nothing to do, yet.*/
7719 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7724 /* Remove the resource from the resourceStore */
7725 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7727 TRACE("Resource released\n");
7731 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7733 IWineD3DResourceImpl *resource, *cursor;
7735 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7737 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7738 TRACE("enumerating resource %p\n", resource);
7739 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7740 ret = pCallback((IWineD3DResource *) resource, pData);
7741 if(ret == S_FALSE) {
7742 TRACE("Canceling enumeration\n");
7749 /**********************************************************
7750 * IWineD3DDevice VTbl follows
7751 **********************************************************/
7753 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7755 /*** IUnknown methods ***/
7756 IWineD3DDeviceImpl_QueryInterface,
7757 IWineD3DDeviceImpl_AddRef,
7758 IWineD3DDeviceImpl_Release,
7759 /*** IWineD3DDevice methods ***/
7760 IWineD3DDeviceImpl_GetParent,
7761 /*** Creation methods**/
7762 IWineD3DDeviceImpl_CreateBuffer,
7763 IWineD3DDeviceImpl_CreateVertexBuffer,
7764 IWineD3DDeviceImpl_CreateIndexBuffer,
7765 IWineD3DDeviceImpl_CreateStateBlock,
7766 IWineD3DDeviceImpl_CreateSurface,
7767 IWineD3DDeviceImpl_CreateRendertargetView,
7768 IWineD3DDeviceImpl_CreateTexture,
7769 IWineD3DDeviceImpl_CreateVolumeTexture,
7770 IWineD3DDeviceImpl_CreateVolume,
7771 IWineD3DDeviceImpl_CreateCubeTexture,
7772 IWineD3DDeviceImpl_CreateQuery,
7773 IWineD3DDeviceImpl_CreateSwapChain,
7774 IWineD3DDeviceImpl_CreateVertexDeclaration,
7775 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7776 IWineD3DDeviceImpl_CreateVertexShader,
7777 IWineD3DDeviceImpl_CreatePixelShader,
7778 IWineD3DDeviceImpl_CreatePalette,
7779 /*** Odd functions **/
7780 IWineD3DDeviceImpl_Init3D,
7781 IWineD3DDeviceImpl_InitGDI,
7782 IWineD3DDeviceImpl_Uninit3D,
7783 IWineD3DDeviceImpl_UninitGDI,
7784 IWineD3DDeviceImpl_SetMultithreaded,
7785 IWineD3DDeviceImpl_EvictManagedResources,
7786 IWineD3DDeviceImpl_GetAvailableTextureMem,
7787 IWineD3DDeviceImpl_GetBackBuffer,
7788 IWineD3DDeviceImpl_GetCreationParameters,
7789 IWineD3DDeviceImpl_GetDeviceCaps,
7790 IWineD3DDeviceImpl_GetDirect3D,
7791 IWineD3DDeviceImpl_GetDisplayMode,
7792 IWineD3DDeviceImpl_SetDisplayMode,
7793 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7794 IWineD3DDeviceImpl_GetRasterStatus,
7795 IWineD3DDeviceImpl_GetSwapChain,
7796 IWineD3DDeviceImpl_Reset,
7797 IWineD3DDeviceImpl_SetDialogBoxMode,
7798 IWineD3DDeviceImpl_SetCursorProperties,
7799 IWineD3DDeviceImpl_SetCursorPosition,
7800 IWineD3DDeviceImpl_ShowCursor,
7801 IWineD3DDeviceImpl_TestCooperativeLevel,
7802 /*** Getters and setters **/
7803 IWineD3DDeviceImpl_SetClipPlane,
7804 IWineD3DDeviceImpl_GetClipPlane,
7805 IWineD3DDeviceImpl_SetClipStatus,
7806 IWineD3DDeviceImpl_GetClipStatus,
7807 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7808 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7809 IWineD3DDeviceImpl_SetDepthStencilSurface,
7810 IWineD3DDeviceImpl_GetDepthStencilSurface,
7811 IWineD3DDeviceImpl_SetGammaRamp,
7812 IWineD3DDeviceImpl_GetGammaRamp,
7813 IWineD3DDeviceImpl_SetIndices,
7814 IWineD3DDeviceImpl_GetIndices,
7815 IWineD3DDeviceImpl_SetBaseVertexIndex,
7816 IWineD3DDeviceImpl_GetBaseVertexIndex,
7817 IWineD3DDeviceImpl_SetLight,
7818 IWineD3DDeviceImpl_GetLight,
7819 IWineD3DDeviceImpl_SetLightEnable,
7820 IWineD3DDeviceImpl_GetLightEnable,
7821 IWineD3DDeviceImpl_SetMaterial,
7822 IWineD3DDeviceImpl_GetMaterial,
7823 IWineD3DDeviceImpl_SetNPatchMode,
7824 IWineD3DDeviceImpl_GetNPatchMode,
7825 IWineD3DDeviceImpl_SetPaletteEntries,
7826 IWineD3DDeviceImpl_GetPaletteEntries,
7827 IWineD3DDeviceImpl_SetPixelShader,
7828 IWineD3DDeviceImpl_GetPixelShader,
7829 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7830 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7831 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7832 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7833 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7834 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7835 IWineD3DDeviceImpl_SetRenderState,
7836 IWineD3DDeviceImpl_GetRenderState,
7837 IWineD3DDeviceImpl_SetRenderTarget,
7838 IWineD3DDeviceImpl_GetRenderTarget,
7839 IWineD3DDeviceImpl_SetFrontBackBuffers,
7840 IWineD3DDeviceImpl_SetSamplerState,
7841 IWineD3DDeviceImpl_GetSamplerState,
7842 IWineD3DDeviceImpl_SetScissorRect,
7843 IWineD3DDeviceImpl_GetScissorRect,
7844 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7845 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7846 IWineD3DDeviceImpl_SetStreamSource,
7847 IWineD3DDeviceImpl_GetStreamSource,
7848 IWineD3DDeviceImpl_SetStreamSourceFreq,
7849 IWineD3DDeviceImpl_GetStreamSourceFreq,
7850 IWineD3DDeviceImpl_SetTexture,
7851 IWineD3DDeviceImpl_GetTexture,
7852 IWineD3DDeviceImpl_SetTextureStageState,
7853 IWineD3DDeviceImpl_GetTextureStageState,
7854 IWineD3DDeviceImpl_SetTransform,
7855 IWineD3DDeviceImpl_GetTransform,
7856 IWineD3DDeviceImpl_SetVertexDeclaration,
7857 IWineD3DDeviceImpl_GetVertexDeclaration,
7858 IWineD3DDeviceImpl_SetVertexShader,
7859 IWineD3DDeviceImpl_GetVertexShader,
7860 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7861 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7862 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7863 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7864 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7865 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7866 IWineD3DDeviceImpl_SetViewport,
7867 IWineD3DDeviceImpl_GetViewport,
7868 IWineD3DDeviceImpl_MultiplyTransform,
7869 IWineD3DDeviceImpl_ValidateDevice,
7870 IWineD3DDeviceImpl_ProcessVertices,
7871 /*** State block ***/
7872 IWineD3DDeviceImpl_BeginStateBlock,
7873 IWineD3DDeviceImpl_EndStateBlock,
7874 /*** Scene management ***/
7875 IWineD3DDeviceImpl_BeginScene,
7876 IWineD3DDeviceImpl_EndScene,
7877 IWineD3DDeviceImpl_Present,
7878 IWineD3DDeviceImpl_Clear,
7879 IWineD3DDeviceImpl_ClearRendertargetView,
7881 IWineD3DDeviceImpl_SetPrimitiveType,
7882 IWineD3DDeviceImpl_GetPrimitiveType,
7883 IWineD3DDeviceImpl_DrawPrimitive,
7884 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7885 IWineD3DDeviceImpl_DrawPrimitiveUP,
7886 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7887 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7888 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7889 IWineD3DDeviceImpl_DrawRectPatch,
7890 IWineD3DDeviceImpl_DrawTriPatch,
7891 IWineD3DDeviceImpl_DeletePatch,
7892 IWineD3DDeviceImpl_ColorFill,
7893 IWineD3DDeviceImpl_UpdateTexture,
7894 IWineD3DDeviceImpl_UpdateSurface,
7895 IWineD3DDeviceImpl_GetFrontBufferData,
7896 /*** object tracking ***/
7897 IWineD3DDeviceImpl_ResourceReleased,
7898 IWineD3DDeviceImpl_EnumResources
7901 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7902 WINED3DRS_ALPHABLENDENABLE ,
7903 WINED3DRS_ALPHAFUNC ,
7904 WINED3DRS_ALPHAREF ,
7905 WINED3DRS_ALPHATESTENABLE ,
7907 WINED3DRS_COLORWRITEENABLE ,
7908 WINED3DRS_DESTBLEND ,
7909 WINED3DRS_DITHERENABLE ,
7910 WINED3DRS_FILLMODE ,
7911 WINED3DRS_FOGDENSITY ,
7913 WINED3DRS_FOGSTART ,
7914 WINED3DRS_LASTPIXEL ,
7915 WINED3DRS_SHADEMODE ,
7916 WINED3DRS_SRCBLEND ,
7917 WINED3DRS_STENCILENABLE ,
7918 WINED3DRS_STENCILFAIL ,
7919 WINED3DRS_STENCILFUNC ,
7920 WINED3DRS_STENCILMASK ,
7921 WINED3DRS_STENCILPASS ,
7922 WINED3DRS_STENCILREF ,
7923 WINED3DRS_STENCILWRITEMASK ,
7924 WINED3DRS_STENCILZFAIL ,
7925 WINED3DRS_TEXTUREFACTOR ,
7936 WINED3DRS_ZWRITEENABLE
7939 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7940 WINED3DTSS_ALPHAARG0 ,
7941 WINED3DTSS_ALPHAARG1 ,
7942 WINED3DTSS_ALPHAARG2 ,
7943 WINED3DTSS_ALPHAOP ,
7944 WINED3DTSS_BUMPENVLOFFSET ,
7945 WINED3DTSS_BUMPENVLSCALE ,
7946 WINED3DTSS_BUMPENVMAT00 ,
7947 WINED3DTSS_BUMPENVMAT01 ,
7948 WINED3DTSS_BUMPENVMAT10 ,
7949 WINED3DTSS_BUMPENVMAT11 ,
7950 WINED3DTSS_COLORARG0 ,
7951 WINED3DTSS_COLORARG1 ,
7952 WINED3DTSS_COLORARG2 ,
7953 WINED3DTSS_COLOROP ,
7954 WINED3DTSS_RESULTARG ,
7955 WINED3DTSS_TEXCOORDINDEX ,
7956 WINED3DTSS_TEXTURETRANSFORMFLAGS
7959 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7960 WINED3DSAMP_ADDRESSU ,
7961 WINED3DSAMP_ADDRESSV ,
7962 WINED3DSAMP_ADDRESSW ,
7963 WINED3DSAMP_BORDERCOLOR ,
7964 WINED3DSAMP_MAGFILTER ,
7965 WINED3DSAMP_MINFILTER ,
7966 WINED3DSAMP_MIPFILTER ,
7967 WINED3DSAMP_MIPMAPLODBIAS ,
7968 WINED3DSAMP_MAXMIPLEVEL ,
7969 WINED3DSAMP_MAXANISOTROPY ,
7970 WINED3DSAMP_SRGBTEXTURE ,
7971 WINED3DSAMP_ELEMENTINDEX
7974 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7976 WINED3DRS_AMBIENTMATERIALSOURCE ,
7977 WINED3DRS_CLIPPING ,
7978 WINED3DRS_CLIPPLANEENABLE ,
7979 WINED3DRS_COLORVERTEX ,
7980 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7981 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7982 WINED3DRS_FOGDENSITY ,
7984 WINED3DRS_FOGSTART ,
7985 WINED3DRS_FOGTABLEMODE ,
7986 WINED3DRS_FOGVERTEXMODE ,
7987 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7988 WINED3DRS_LIGHTING ,
7989 WINED3DRS_LOCALVIEWER ,
7990 WINED3DRS_MULTISAMPLEANTIALIAS ,
7991 WINED3DRS_MULTISAMPLEMASK ,
7992 WINED3DRS_NORMALIZENORMALS ,
7993 WINED3DRS_PATCHEDGESTYLE ,
7994 WINED3DRS_POINTSCALE_A ,
7995 WINED3DRS_POINTSCALE_B ,
7996 WINED3DRS_POINTSCALE_C ,
7997 WINED3DRS_POINTSCALEENABLE ,
7998 WINED3DRS_POINTSIZE ,
7999 WINED3DRS_POINTSIZE_MAX ,
8000 WINED3DRS_POINTSIZE_MIN ,
8001 WINED3DRS_POINTSPRITEENABLE ,
8002 WINED3DRS_RANGEFOGENABLE ,
8003 WINED3DRS_SPECULARMATERIALSOURCE ,
8004 WINED3DRS_TWEENFACTOR ,
8005 WINED3DRS_VERTEXBLEND ,
8006 WINED3DRS_CULLMODE ,
8010 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8011 WINED3DTSS_TEXCOORDINDEX ,
8012 WINED3DTSS_TEXTURETRANSFORMFLAGS
8015 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8016 WINED3DSAMP_DMAPOFFSET
8019 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8020 DWORD rep = This->StateTable[state].representative;
8024 WineD3DContext *context;
8027 for(i = 0; i < This->numContexts; i++) {
8028 context = This->contexts[i];
8029 if(isStateDirty(context, rep)) continue;
8031 context->dirtyArray[context->numDirtyEntries++] = rep;
8034 context->isStateDirty[idx] |= (1 << shift);
8038 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8039 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8040 /* The drawable size of a pbuffer render target is the current pbuffer size
8042 *width = dev->pbufferWidth;
8043 *height = dev->pbufferHeight;
8046 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8047 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8049 *width = This->pow2Width;
8050 *height = This->pow2Height;
8053 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8054 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8055 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8056 * current context's drawable, which is the size of the back buffer of the swapchain
8057 * the active context belongs to. The back buffer of the swapchain is stored as the
8058 * surface the context belongs to.
8060 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8061 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;