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_desc->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 /* Dummy format for now */
266 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
267 struct wined3d_buffer *object;
268 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
273 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
274 *ppVertexBuffer = NULL;
275 return WINED3DERR_INVALIDCALL;
276 } else if(Pool == WINED3DPOOL_SCRATCH) {
277 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
278 * anyway, SCRATCH vertex buffers aren't usable anywhere
280 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
281 *ppVertexBuffer = NULL;
282 return WINED3DERR_INVALIDCALL;
285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
288 ERR("Out of memory\n");
289 *ppVertexBuffer = NULL;
290 return WINED3DERR_OUTOFVIDEOMEMORY;
293 object->vtbl = &wined3d_buffer_vtbl;
294 hr = resource_init(&object->resource, WINED3DRTYPE_VERTEXBUFFER, This, Size, Usage, format_desc, Pool, parent);
297 WARN("Failed to initialize resource, returning %#x\n", hr);
298 HeapFree(GetProcessHeap(), 0, object);
299 *ppVertexBuffer = NULL;
303 TRACE("(%p) : Created resource %p\n", This, object);
305 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
307 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
308 *ppVertexBuffer = (IWineD3DBuffer *)object;
312 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
313 * drawStridedFast (half-life 2).
315 * Basically converting the vertices in the buffer is quite expensive, and observations
316 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
317 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
319 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
320 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
321 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
322 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
324 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
325 * more. In this call we can convert dx7 buffers too.
327 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
328 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
329 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
330 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
331 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
332 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
333 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
334 } else if(dxVersion <= 7 && conv) {
335 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
337 object->flags |= WINED3D_BUFFER_CREATEBO;
342 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
343 GLenum error, glUsage;
344 TRACE("Creating VBO for Index Buffer %p\n", object);
346 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
347 * restored on the next draw
349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
351 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
352 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
357 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
358 error = glGetError();
359 if(error != GL_NO_ERROR || object->vbo == 0) {
360 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
364 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
365 error = glGetError();
366 if(error != GL_NO_ERROR) {
367 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
371 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
372 * copy no readback will be needed
374 glUsage = GL_STATIC_DRAW_ARB;
375 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
376 error = glGetError();
377 if(error != GL_NO_ERROR) {
378 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
382 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
386 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
387 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
392 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
393 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
394 HANDLE *sharedHandle, IUnknown *parent) {
395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
397 IWineD3DIndexBufferImpl *object;
400 TRACE("(%p) Creating index buffer\n", This);
402 /* Allocate the storage for the device */
403 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
406 ERR("Out of memory\n");
407 *ppIndexBuffer = NULL;
408 return WINED3DERR_OUTOFVIDEOMEMORY;
411 object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
412 hr = resource_init(&object->resource, WINED3DRTYPE_INDEXBUFFER, This, Length, Usage, format_desc, Pool, parent);
415 WARN("Failed to initialize resource, returning %#x\n", hr);
416 HeapFree(GetProcessHeap(), 0, object);
417 *ppIndexBuffer = NULL;
421 TRACE("(%p) : Created resource %p\n", This, object);
423 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
443 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
446 ERR("Out of memory\n");
447 *ppStateBlock = NULL;
448 return WINED3DERR_OUTOFVIDEOMEMORY;
451 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
452 object->wineD3DDevice = This;
453 object->parent = parent;
455 object->blockType = Type;
457 *ppStateBlock = (IWineD3DStateBlock *)object;
459 for(i = 0; i < LIGHTMAP_SIZE; i++) {
460 list_init(&object->lightMap[i]);
463 temp_result = allocate_shader_constants(object);
464 if (FAILED(temp_result))
466 HeapFree(GetProcessHeap(), 0, object);
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
474 /* Don't bother increasing the reference count otherwise a device will never
475 be freed due to circular dependencies */
479 /* Otherwise, might as well set the whole state block to the appropriate values */
480 if (This->stateBlock != NULL)
481 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
483 memset(object->streamFreq, 1, sizeof(object->streamFreq));
485 /* Reset the ref and type after kludging it */
486 object->wineD3DDevice = This;
488 object->blockType = Type;
490 TRACE("Updating changed flags appropriate for type %d\n", Type);
492 if (Type == WINED3DSBT_ALL) {
494 TRACE("ALL => Pretend everything has changed\n");
495 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
497 /* Lights are not part of the changed / set structure */
498 for(j = 0; j < LIGHTMAP_SIZE; j++) {
500 LIST_FOR_EACH(e, &object->lightMap[j]) {
501 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
502 light->changed = TRUE;
503 light->enabledChanged = TRUE;
506 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
507 object->contained_render_states[j - 1] = j;
509 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
510 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
511 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
512 object->contained_transform_states[j - 1] = j;
514 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
515 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
516 object->contained_vs_consts_f[j] = j;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for(j = 0; j < MAX_CONST_I; j++) {
520 object->contained_vs_consts_i[j] = j;
522 object->num_contained_vs_consts_i = MAX_CONST_I;
523 for(j = 0; j < MAX_CONST_B; j++) {
524 object->contained_vs_consts_b[j] = j;
526 object->num_contained_vs_consts_b = MAX_CONST_B;
527 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
528 object->contained_ps_consts_f[j] = j;
530 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
531 for(j = 0; j < MAX_CONST_I; j++) {
532 object->contained_ps_consts_i[j] = j;
534 object->num_contained_ps_consts_i = MAX_CONST_I;
535 for(j = 0; j < MAX_CONST_B; j++) {
536 object->contained_ps_consts_b[j] = j;
538 object->num_contained_ps_consts_b = MAX_CONST_B;
539 for(i = 0; i < MAX_TEXTURES; i++) {
540 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
542 object->contained_tss_states[object->num_contained_tss_states].stage = i;
543 object->contained_tss_states[object->num_contained_tss_states].state = j;
544 object->num_contained_tss_states++;
547 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
548 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
549 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
550 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
551 object->num_contained_sampler_states++;
555 for(i = 0; i < MAX_STREAMS; i++) {
556 if(object->streamSource[i]) {
557 IWineD3DBuffer_AddRef(object->streamSource[i]);
560 if(object->pIndexData) {
561 IWineD3DIndexBuffer_AddRef(object->pIndexData);
563 if(object->vertexShader) {
564 IWineD3DVertexShader_AddRef(object->vertexShader);
566 if(object->pixelShader) {
567 IWineD3DPixelShader_AddRef(object->pixelShader);
570 } else if (Type == WINED3DSBT_PIXELSTATE) {
572 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
573 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
575 object->changed.pixelShader = TRUE;
577 /* Pixel Shader Constants */
578 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
579 object->contained_ps_consts_f[i] = i;
580 object->changed.pixelShaderConstantsF[i] = TRUE;
582 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
583 for (i = 0; i < MAX_CONST_B; ++i) {
584 object->contained_ps_consts_b[i] = i;
585 object->changed.pixelShaderConstantsB |= (1 << i);
587 object->num_contained_ps_consts_b = MAX_CONST_B;
588 for (i = 0; i < MAX_CONST_I; ++i) {
589 object->contained_ps_consts_i[i] = i;
590 object->changed.pixelShaderConstantsI |= (1 << i);
592 object->num_contained_ps_consts_i = MAX_CONST_I;
594 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
595 DWORD rs = SavedPixelStates_R[i];
596 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
597 object->contained_render_states[i] = rs;
599 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
600 for (j = 0; j < MAX_TEXTURES; j++) {
601 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
602 DWORD state = SavedPixelStates_T[i];
603 object->changed.textureState[j] |= 1 << state;
604 object->contained_tss_states[object->num_contained_tss_states].stage = j;
605 object->contained_tss_states[object->num_contained_tss_states].state = state;
606 object->num_contained_tss_states++;
609 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
610 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
611 DWORD state = SavedPixelStates_S[i];
612 object->changed.samplerState[j] |= 1 << state;
613 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
614 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
615 object->num_contained_sampler_states++;
618 if(object->pixelShader) {
619 IWineD3DPixelShader_AddRef(object->pixelShader);
622 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
623 * on them. This makes releasing the buffer easier
625 for(i = 0; i < MAX_STREAMS; i++) {
626 object->streamSource[i] = NULL;
628 object->pIndexData = NULL;
629 object->vertexShader = NULL;
631 } else if (Type == WINED3DSBT_VERTEXSTATE) {
633 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
634 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
636 object->changed.vertexShader = TRUE;
638 /* Vertex Shader Constants */
639 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
640 object->changed.vertexShaderConstantsF[i] = TRUE;
641 object->contained_vs_consts_f[i] = i;
643 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
644 for (i = 0; i < MAX_CONST_B; ++i) {
645 object->contained_vs_consts_b[i] = i;
646 object->changed.vertexShaderConstantsB |= (1 << i);
648 object->num_contained_vs_consts_b = MAX_CONST_B;
649 for (i = 0; i < MAX_CONST_I; ++i) {
650 object->contained_vs_consts_i[i] = i;
651 object->changed.vertexShaderConstantsI |= (1 << i);
653 object->num_contained_vs_consts_i = MAX_CONST_I;
654 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
655 DWORD rs = SavedVertexStates_R[i];
656 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
657 object->contained_render_states[i] = rs;
659 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
660 for (j = 0; j < MAX_TEXTURES; j++) {
661 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
662 DWORD state = SavedVertexStates_T[i];
663 object->changed.textureState[j] |= 1 << state;
664 object->contained_tss_states[object->num_contained_tss_states].stage = j;
665 object->contained_tss_states[object->num_contained_tss_states].state = state;
666 object->num_contained_tss_states++;
669 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
670 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
671 DWORD state = SavedVertexStates_S[i];
672 object->changed.samplerState[j] |= 1 << state;
673 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
674 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
675 object->num_contained_sampler_states++;
679 for(j = 0; j < LIGHTMAP_SIZE; j++) {
681 LIST_FOR_EACH(e, &object->lightMap[j]) {
682 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
683 light->changed = TRUE;
684 light->enabledChanged = TRUE;
688 for(i = 0; i < MAX_STREAMS; i++) {
689 if(object->streamSource[i]) {
690 IWineD3DBuffer_AddRef(object->streamSource[i]);
693 if(object->vertexShader) {
694 IWineD3DVertexShader_AddRef(object->vertexShader);
696 object->pIndexData = NULL;
697 object->pixelShader = NULL;
699 FIXME("Unrecognized state block type %d\n", Type);
702 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
708 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
709 unsigned int Size = 1;
710 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
714 TRACE("(%p) Create surface\n",This);
716 if(MultisampleQuality > 0) {
717 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
718 MultisampleQuality=0;
721 /** FIXME: Check that the format is supported
723 *******************************/
725 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
726 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
728 *********************************/
729 mul_4w = (Width + 3) & ~3;
730 mul_4h = (Height + 3) & ~3;
731 if (WINED3DFMT_UNKNOWN == Format) {
733 } else if (Format == WINED3DFMT_DXT1) {
734 /* DXT1 is half byte per pixel */
735 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
737 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
738 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
739 Format == WINED3DFMT_ATI2N) {
740 Size = (mul_4w * glDesc->byte_count * mul_4h);
742 /* The pitch is a multiple of 4 bytes */
743 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
747 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
749 /** Create and initialise the surface resource **/
750 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
753 ERR("Out of memory\n");
755 return WINED3DERR_OUTOFVIDEOMEMORY;
758 /* Look at the implementation and set the correct Vtable */
762 /* Check if a 3D adapter is available when creating gl surfaces */
765 ERR("OpenGL surfaces are not available without opengl\n");
766 HeapFree(GetProcessHeap(), 0, object);
767 return WINED3DERR_NOTAVAILABLE;
769 object->lpVtbl = &IWineD3DSurface_Vtbl;
773 object->lpVtbl = &IWineGDISurface_Vtbl;
777 /* To be sure to catch this */
778 ERR("Unknown requested surface implementation %d!\n", Impl);
779 HeapFree(GetProcessHeap(), 0, object);
780 return WINED3DERR_INVALIDCALL;
783 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
786 WARN("Failed to initialize resource, returning %#x\n", hr);
787 HeapFree(GetProcessHeap(), 0, object);
792 TRACE("(%p) : Created resource %p\n", This, object);
794 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
796 *ppSurface = (IWineD3DSurface *)object;
798 /* "Standalone" surface */
799 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
801 object->currentDesc.Width = Width;
802 object->currentDesc.Height = Height;
803 object->currentDesc.MultiSampleType = MultiSample;
804 object->currentDesc.MultiSampleQuality = MultisampleQuality;
805 object->glDescription.level = Level;
806 list_init(&object->overlays);
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;
814 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
816 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
817 * this function is too deep to need to care about things like this.
818 * Levels need to be checked too, and possibly Type since they all affect what can be done.
819 * ****************************************/
821 case WINED3DPOOL_SCRATCH:
823 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
824 "which are mutually exclusive, setting lockable to TRUE\n");
827 case WINED3DPOOL_SYSTEMMEM:
828 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
829 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
830 case WINED3DPOOL_MANAGED:
831 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
832 "Usage of DYNAMIC which are mutually exclusive, not doing "
833 "anything just telling you.\n");
835 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
836 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
837 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
838 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
841 FIXME("(%p) Unknown pool %d\n", This, Pool);
845 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
846 FIXME("Trying to create a render target that isn't in the default pool\n");
849 /* mark the texture as dirty so that it gets loaded first time around*/
850 surface_add_dirty_rect(*ppSurface, NULL);
851 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
852 This, Width, Height, Format, debug_d3dformat(Format),
853 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
855 list_init(&object->renderbuffers);
857 /* Call the private setup routine */
858 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
861 ERR("Private setup failed, returning %#x\n", hr);
862 IWineD3DSurface_Release(*ppSurface);
870 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
871 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
873 struct wined3d_rendertarget_view *object;
875 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
878 ERR("Failed to allocate memory\n");
879 return E_OUTOFMEMORY;
882 object->vtbl = &wined3d_rendertarget_view_vtbl;
883 object->refcount = 1;
884 IWineD3DResource_AddRef(resource);
885 object->resource = resource;
886 object->parent = parent;
888 *rendertarget_view = (IWineD3DRendertargetView *)object;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
895 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
899 IWineD3DTextureImpl *object;
904 unsigned int pow2Width;
905 unsigned int pow2Height;
907 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
908 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
909 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
918 /* Non-power2 support */
919 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
926 /* Find the nearest pow2 match */
927 pow2Width = pow2Height = 1;
928 while (pow2Width < Width) pow2Width <<= 1;
929 while (pow2Height < Height) pow2Height <<= 1;
931 if (pow2Width != Width || pow2Height != Height)
935 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
936 return WINED3DERR_INVALIDCALL;
942 /* Calculate levels for mip mapping */
943 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
945 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
947 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
948 return WINED3DERR_INVALIDCALL;
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
961 Levels = wined3d_log2i(max(Width, Height)) + 1;
962 TRACE("Calculated levels = %d\n", Levels);
965 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
968 ERR("Out of memory\n");
970 return WINED3DERR_OUTOFVIDEOMEMORY;
973 object->lpVtbl = &IWineD3DTexture_Vtbl;
974 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
977 WARN("Failed to initialize resource, returning %#x\n", hr);
978 HeapFree(GetProcessHeap(), 0, object);
983 TRACE("(%p) : Created resource %p\n", This, object);
985 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
987 *ppTexture = (IWineD3DTexture *)object;
989 basetexture_init(&object->baseTexture, Levels, Usage);
991 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
993 object->baseTexture.minMipLookup = minMipLookup;
994 object->baseTexture.magLookup = magLookup;
996 object->baseTexture.minMipLookup = minMipLookup_noFilter;
997 object->baseTexture.magLookup = magLookup_noFilter;
1000 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1001 /* Precalculated scaling for 'faked' non power of two texture coords.
1002 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1003 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1004 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1006 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1007 object->baseTexture.pow2Matrix[0] = 1.0;
1008 object->baseTexture.pow2Matrix[5] = 1.0;
1009 object->baseTexture.pow2Matrix[10] = 1.0;
1010 object->baseTexture.pow2Matrix[15] = 1.0;
1011 object->target = GL_TEXTURE_2D;
1012 object->cond_np2 = TRUE;
1013 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1014 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1015 (Width != pow2Width || Height != pow2Height) &&
1016 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1018 object->baseTexture.pow2Matrix[0] = (float)Width;
1019 object->baseTexture.pow2Matrix[5] = (float)Height;
1020 object->baseTexture.pow2Matrix[10] = 1.0;
1021 object->baseTexture.pow2Matrix[15] = 1.0;
1022 object->target = GL_TEXTURE_RECTANGLE_ARB;
1023 object->cond_np2 = TRUE;
1024 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1026 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1027 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1028 object->baseTexture.pow2Matrix[10] = 1.0;
1029 object->baseTexture.pow2Matrix[15] = 1.0;
1030 object->target = GL_TEXTURE_2D;
1031 object->cond_np2 = FALSE;
1033 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1035 /* Generate all the surfaces */
1038 for (i = 0; i < object->baseTexture.levels; i++)
1040 /* use the callback to create the texture surface */
1041 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1042 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1043 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1044 FIXME("Failed to create surface %p\n", object);
1046 object->surfaces[i] = NULL;
1047 IWineD3DTexture_Release((IWineD3DTexture *)object);
1053 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1054 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1055 surface_set_texture_target(object->surfaces[i], object->target);
1056 /* calculate the next mipmap level */
1057 tmpW = max(1, tmpW >> 1);
1058 tmpH = max(1, tmpH >> 1);
1060 object->baseTexture.internal_preload = texture_internal_preload;
1062 TRACE("(%p) : Created texture %p\n", This, object);
1066 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1067 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1068 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1072 IWineD3DVolumeTextureImpl *object;
1079 /* TODO: It should only be possible to create textures for formats
1080 that are reported as supported */
1081 if (WINED3DFMT_UNKNOWN >= Format) {
1082 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1083 return WINED3DERR_INVALIDCALL;
1085 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1086 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 /* Calculate levels for mip mapping */
1091 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1093 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1095 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1096 return WINED3DERR_INVALIDCALL;
1101 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1102 return WINED3DERR_INVALIDCALL;
1109 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1110 TRACE("Calculated levels = %d\n", Levels);
1113 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1116 ERR("Out of memory\n");
1117 *ppVolumeTexture = NULL;
1118 return WINED3DERR_OUTOFVIDEOMEMORY;
1121 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1122 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1125 WARN("Failed to initialize resource, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1127 *ppVolumeTexture = NULL;
1131 TRACE("(%p) : Created resource %p\n", This, object);
1133 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1135 basetexture_init(&object->baseTexture, Levels, Usage);
1137 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1138 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1140 /* Is NP2 support for volumes needed? */
1141 object->baseTexture.pow2Matrix[ 0] = 1.0;
1142 object->baseTexture.pow2Matrix[ 5] = 1.0;
1143 object->baseTexture.pow2Matrix[10] = 1.0;
1144 object->baseTexture.pow2Matrix[15] = 1.0;
1146 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1148 object->baseTexture.minMipLookup = minMipLookup;
1149 object->baseTexture.magLookup = magLookup;
1151 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1152 object->baseTexture.magLookup = magLookup_noFilter;
1155 /* Generate all the surfaces */
1160 for (i = 0; i < object->baseTexture.levels; i++)
1163 /* Create the volume */
1164 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1165 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1167 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1168 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1169 *ppVolumeTexture = NULL;
1173 /* Set its container to this object */
1174 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1176 /* calculate the next mipmap level */
1177 tmpW = max(1, tmpW >> 1);
1178 tmpH = max(1, tmpH >> 1);
1179 tmpD = max(1, tmpD >> 1);
1181 object->baseTexture.internal_preload = volumetexture_internal_preload;
1183 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1184 TRACE("(%p) : Created volume texture %p\n", This, object);
1188 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1189 UINT Width, UINT Height, UINT Depth,
1191 WINED3DFORMAT Format, WINED3DPOOL Pool,
1192 IWineD3DVolume** ppVolume,
1193 HANDLE* pSharedHandle, IUnknown *parent) {
1195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1196 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1197 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1200 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1201 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1202 return WINED3DERR_INVALIDCALL;
1205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1208 ERR("Out of memory\n");
1210 return WINED3DERR_OUTOFVIDEOMEMORY;
1213 object->lpVtbl = &IWineD3DVolume_Vtbl;
1214 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1215 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1218 WARN("Failed to initialize resource, returning %#x\n", hr);
1219 HeapFree(GetProcessHeap(), 0, object);
1224 TRACE("(%p) : Created resource %p\n", This, object);
1226 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1228 *ppVolume = (IWineD3DVolume *)object;
1230 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1231 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1233 object->currentDesc.Width = Width;
1234 object->currentDesc.Height = Height;
1235 object->currentDesc.Depth = Depth;
1237 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1238 object->lockable = TRUE;
1239 object->locked = FALSE;
1240 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1241 object->dirty = TRUE;
1243 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1249 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1250 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1253 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1254 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1258 unsigned int pow2EdgeLength;
1260 /* TODO: It should only be possible to create textures for formats
1261 that are reported as supported */
1262 if (WINED3DFMT_UNKNOWN >= Format) {
1263 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1264 return WINED3DERR_INVALIDCALL;
1267 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1268 WARN("(%p) : Tried to create not supported cube texture\n", This);
1269 return WINED3DERR_INVALIDCALL;
1272 /* Calculate levels for mip mapping */
1273 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1275 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1277 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1278 return WINED3DERR_INVALIDCALL;
1283 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1284 return WINED3DERR_INVALIDCALL;
1291 Levels = wined3d_log2i(EdgeLength) + 1;
1292 TRACE("Calculated levels = %d\n", Levels);
1295 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1298 ERR("Out of memory\n");
1299 *ppCubeTexture = NULL;
1300 return WINED3DERR_OUTOFVIDEOMEMORY;
1303 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1304 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1307 WARN("Failed to initialize resource, returning %#x\n", hr);
1308 HeapFree(GetProcessHeap(), 0, object);
1309 *ppCubeTexture = NULL;
1313 TRACE("(%p) : Created resource %p\n", This, object);
1315 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1317 basetexture_init(&object->baseTexture, Levels, Usage);
1319 TRACE("(%p) Create Cube Texture\n", This);
1321 /* Find the nearest pow2 match */
1323 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1325 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1326 /* Precalculated scaling for 'faked' non power of two texture coords */
1327 object->baseTexture.pow2Matrix[ 0] = 1.0;
1328 object->baseTexture.pow2Matrix[ 5] = 1.0;
1329 object->baseTexture.pow2Matrix[10] = 1.0;
1330 object->baseTexture.pow2Matrix[15] = 1.0;
1332 /* Precalculated scaling for 'faked' non power of two texture coords */
1333 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1334 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1335 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1336 object->baseTexture.pow2Matrix[15] = 1.0;
1339 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1341 object->baseTexture.minMipLookup = minMipLookup;
1342 object->baseTexture.magLookup = magLookup;
1344 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1345 object->baseTexture.magLookup = magLookup_noFilter;
1348 /* Generate all the surfaces */
1350 for (i = 0; i < object->baseTexture.levels; i++) {
1352 /* Create the 6 faces */
1353 for (j = 0; j < 6; j++) {
1354 static const GLenum cube_targets[6] = {
1355 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1356 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1357 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1358 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1359 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1360 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1363 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1364 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1369 *ppCubeTexture = NULL;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1374 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1376 tmpW = max(1, tmpW >> 1);
1378 object->baseTexture.internal_preload = cubetexture_internal_preload;
1380 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1381 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1387 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1388 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1389 const IWineD3DQueryVtbl *vtable;
1391 /* Just a check to see if we support this type of query */
1393 case WINED3DQUERYTYPE_OCCLUSION:
1394 TRACE("(%p) occlusion query\n", This);
1395 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1398 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1400 vtable = &IWineD3DOcclusionQuery_Vtbl;
1403 case WINED3DQUERYTYPE_EVENT:
1404 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1405 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1406 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1408 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1410 vtable = &IWineD3DEventQuery_Vtbl;
1414 case WINED3DQUERYTYPE_VCACHE:
1415 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1416 case WINED3DQUERYTYPE_VERTEXSTATS:
1417 case WINED3DQUERYTYPE_TIMESTAMP:
1418 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1419 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1420 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1421 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1422 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1423 case WINED3DQUERYTYPE_PIXELTIMINGS:
1424 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1425 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1427 /* Use the base Query vtable until we have a special one for each query */
1428 vtable = &IWineD3DQuery_Vtbl;
1429 FIXME("(%p) Unhandled query type %d\n", This, Type);
1431 if(NULL == ppQuery || hr != WINED3D_OK) {
1435 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1438 ERR("Out of memory\n");
1440 return WINED3DERR_OUTOFVIDEOMEMORY;
1443 object->lpVtbl = vtable;
1444 object->type = Type;
1445 object->state = QUERY_CREATED;
1446 object->wineD3DDevice = This;
1447 object->parent = parent;
1450 *ppQuery = (IWineD3DQuery *)object;
1452 /* allocated the 'extended' data based on the type of query requested */
1454 case WINED3DQUERYTYPE_OCCLUSION:
1455 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1458 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1459 TRACE("(%p) Allocating data for an occlusion query\n", This);
1461 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1463 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1467 case WINED3DQUERYTYPE_EVENT:
1468 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1469 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1471 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1473 if(GL_SUPPORT(APPLE_FENCE)) {
1474 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1475 checkGLcall("glGenFencesAPPLE");
1476 } else if(GL_SUPPORT(NV_FENCE)) {
1477 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1478 checkGLcall("glGenFencesNV");
1483 case WINED3DQUERYTYPE_VCACHE:
1484 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1485 case WINED3DQUERYTYPE_VERTEXSTATS:
1486 case WINED3DQUERYTYPE_TIMESTAMP:
1487 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1488 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1489 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1490 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1491 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1492 case WINED3DQUERYTYPE_PIXELTIMINGS:
1493 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1494 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1496 object->extendedData = 0;
1497 FIXME("(%p) Unhandled query type %d\n",This , Type);
1499 TRACE("(%p) : Created Query %p\n", This, object);
1503 /*****************************************************************************
1504 * IWineD3DDeviceImpl_SetupFullscreenWindow
1506 * Helper function that modifies a HWND's Style and ExStyle for proper
1510 * iface: Pointer to the IWineD3DDevice interface
1511 * window: Window to setup
1513 *****************************************************************************/
1514 static LONG fullscreen_style(LONG orig_style) {
1515 LONG style = orig_style;
1516 style &= ~WS_CAPTION;
1517 style &= ~WS_THICKFRAME;
1519 /* Make sure the window is managed, otherwise we won't get keyboard input */
1520 style |= WS_POPUP | WS_SYSMENU;
1525 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1526 LONG exStyle = orig_exStyle;
1528 /* Filter out window decorations */
1529 exStyle &= ~WS_EX_WINDOWEDGE;
1530 exStyle &= ~WS_EX_CLIENTEDGE;
1535 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 LONG style, exStyle;
1539 /* Don't do anything if an original style is stored.
1540 * That shouldn't happen
1542 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1543 if (This->style || This->exStyle) {
1544 ERR("(%p): Want to change the window parameters of HWND %p, but "
1545 "another style is stored for restoration afterwards\n", This, window);
1548 /* Get the parameters and save them */
1549 style = GetWindowLongW(window, GWL_STYLE);
1550 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1551 This->style = style;
1552 This->exStyle = exStyle;
1554 style = fullscreen_style(style);
1555 exStyle = fullscreen_exStyle(exStyle);
1557 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1558 This->style, This->exStyle, style, exStyle);
1560 SetWindowLongW(window, GWL_STYLE, style);
1561 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1563 /* Inform the window about the update. */
1564 SetWindowPos(window, HWND_TOP, 0, 0,
1565 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1568 /*****************************************************************************
1569 * IWineD3DDeviceImpl_RestoreWindow
1571 * Helper function that restores a windows' properties when taking it out
1572 * of fullscreen mode
1575 * iface: Pointer to the IWineD3DDevice interface
1576 * window: Window to setup
1578 *****************************************************************************/
1579 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 LONG style, exStyle;
1583 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1584 * switch, do nothing
1586 if (!This->style && !This->exStyle) return;
1588 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1589 This, window, This->style, This->exStyle);
1591 style = GetWindowLongW(window, GWL_STYLE);
1592 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1594 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1595 * Some applications change it before calling Reset() when switching between windowed and
1596 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1598 if(style == fullscreen_style(This->style) &&
1599 exStyle == fullscreen_style(This->exStyle)) {
1600 SetWindowLongW(window, GWL_STYLE, This->style);
1601 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1604 /* Delete the old values */
1608 /* Inform the window about the update */
1609 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1610 0, 0, 0, 0, /* Pos, Size, ignored */
1611 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1614 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1615 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1616 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1617 IUnknown *parent, WINED3DSURFTYPE surface_type)
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1622 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1624 IUnknown *bufferParent;
1625 BOOL displaymode_set = FALSE;
1626 WINED3DDISPLAYMODE Mode;
1627 const struct GlPixelFormatDesc *format_desc;
1629 TRACE("(%p) : Created Additional Swap Chain\n", This);
1631 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1632 * does a device hold a reference to a swap chain giving them a lifetime of the device
1633 * or does the swap chain notify the device of its destruction.
1634 *******************************/
1636 /* Check the params */
1637 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1638 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1639 return WINED3DERR_INVALIDCALL;
1640 } else if (pPresentationParameters->BackBufferCount > 1) {
1641 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");
1644 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1647 ERR("Out of memory\n");
1648 *ppSwapChain = NULL;
1649 return WINED3DERR_OUTOFVIDEOMEMORY;
1652 switch(surface_type) {
1654 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1656 case SURFACE_OPENGL:
1657 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1659 case SURFACE_UNKNOWN:
1660 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1661 HeapFree(GetProcessHeap(), 0, object);
1662 return WINED3DERR_INVALIDCALL;
1664 object->wineD3DDevice = This;
1665 object->parent = parent;
1668 *ppSwapChain = (IWineD3DSwapChain *)object;
1670 /*********************
1671 * Lookup the window Handle and the relating X window handle
1672 ********************/
1674 /* Setup hwnd we are using, plus which display this equates to */
1675 object->win_handle = pPresentationParameters->hDeviceWindow;
1676 if (!object->win_handle) {
1677 object->win_handle = This->createParms.hFocusWindow;
1679 if(!pPresentationParameters->Windowed && object->win_handle) {
1680 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1681 pPresentationParameters->BackBufferWidth,
1682 pPresentationParameters->BackBufferHeight);
1685 hDc = GetDC(object->win_handle);
1686 TRACE("Using hDc %p\n", hDc);
1689 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1690 return WINED3DERR_NOTAVAILABLE;
1693 /* Get info on the current display setup */
1694 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1695 object->orig_width = Mode.Width;
1696 object->orig_height = Mode.Height;
1697 object->orig_fmt = Mode.Format;
1698 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1700 if (pPresentationParameters->Windowed &&
1701 ((pPresentationParameters->BackBufferWidth == 0) ||
1702 (pPresentationParameters->BackBufferHeight == 0) ||
1703 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1706 GetClientRect(object->win_handle, &Rect);
1708 if (pPresentationParameters->BackBufferWidth == 0) {
1709 pPresentationParameters->BackBufferWidth = Rect.right;
1710 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1712 if (pPresentationParameters->BackBufferHeight == 0) {
1713 pPresentationParameters->BackBufferHeight = Rect.bottom;
1714 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1716 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1717 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1718 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1722 /* Put the correct figures in the presentation parameters */
1723 TRACE("Copying across presentation parameters\n");
1724 object->presentParms = *pPresentationParameters;
1726 TRACE("calling rendertarget CB\n");
1727 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1728 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1729 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1730 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1731 if (SUCCEEDED(hr)) {
1732 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1733 if(surface_type == SURFACE_OPENGL) {
1734 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1737 ERR("Failed to create the front buffer\n");
1741 /*********************
1742 * Windowed / Fullscreen
1743 *******************/
1746 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1747 * so we should really check to see if there is a fullscreen swapchain already
1748 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1749 **************************************/
1751 if (!pPresentationParameters->Windowed) {
1752 WINED3DDISPLAYMODE mode;
1755 /* Change the display settings */
1756 mode.Width = pPresentationParameters->BackBufferWidth;
1757 mode.Height = pPresentationParameters->BackBufferHeight;
1758 mode.Format = pPresentationParameters->BackBufferFormat;
1759 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1761 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1762 displaymode_set = TRUE;
1766 * Create an opengl context for the display visual
1767 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1768 * use different properties after that point in time. FIXME: How to handle when requested format
1769 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1770 * it chooses is identical to the one already being used!
1771 **********************************/
1772 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1774 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1775 if(!object->context) {
1776 ERR("Failed to create the context array\n");
1780 object->num_contexts = 1;
1782 if(surface_type == SURFACE_OPENGL) {
1783 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1784 if (!object->context[0]) {
1785 ERR("Failed to create a new context\n");
1786 hr = WINED3DERR_NOTAVAILABLE;
1789 TRACE("Context created (HWND=%p, glContext=%p)\n",
1790 object->win_handle, object->context[0]->glCtx);
1794 /*********************
1795 * Create the back, front and stencil buffers
1796 *******************/
1797 if(object->presentParms.BackBufferCount > 0) {
1800 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1801 if(!object->backBuffer) {
1802 ERR("Out of memory\n");
1807 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1808 TRACE("calling rendertarget CB\n");
1809 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1810 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1811 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1812 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1814 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1816 ERR("Cannot create new back buffer\n");
1819 if(surface_type == SURFACE_OPENGL) {
1821 glDrawBuffer(GL_BACK);
1822 checkGLcall("glDrawBuffer(GL_BACK)");
1827 object->backBuffer = NULL;
1829 /* Single buffering - draw to front buffer */
1830 if(surface_type == SURFACE_OPENGL) {
1832 glDrawBuffer(GL_FRONT);
1833 checkGLcall("glDrawBuffer(GL_FRONT)");
1838 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1839 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1840 TRACE("Creating depth stencil buffer\n");
1841 if (This->auto_depth_stencil_buffer == NULL ) {
1842 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1843 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1844 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1845 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1846 &This->auto_depth_stencil_buffer);
1847 if (SUCCEEDED(hr)) {
1848 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1850 ERR("Failed to create the auto depth stencil\n");
1856 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1858 TRACE("Created swapchain %p\n", object);
1859 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1863 if (displaymode_set) {
1867 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1870 /* Change the display settings */
1871 memset(&devmode, 0, sizeof(devmode));
1872 devmode.dmSize = sizeof(devmode);
1873 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1874 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1875 devmode.dmPelsWidth = object->orig_width;
1876 devmode.dmPelsHeight = object->orig_height;
1877 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1880 if (object->backBuffer) {
1882 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1883 if(object->backBuffer[i]) {
1884 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1885 IUnknown_Release(bufferParent); /* once for the get parent */
1886 if (IUnknown_Release(bufferParent) > 0) {
1887 FIXME("(%p) Something's still holding the back buffer\n",This);
1891 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1892 object->backBuffer = NULL;
1894 if(object->context && object->context[0])
1895 DestroyContext(This, object->context[0]);
1896 if(object->frontBuffer) {
1897 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1898 IUnknown_Release(bufferParent); /* once for the get parent */
1899 if (IUnknown_Release(bufferParent) > 0) {
1900 FIXME("(%p) Something's still holding the front buffer\n",This);
1903 HeapFree(GetProcessHeap(), 0, object);
1907 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1908 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 TRACE("(%p)\n", This);
1912 return This->NumberOfSwapChains;
1915 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1917 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1919 if(iSwapChain < This->NumberOfSwapChains) {
1920 *pSwapChain = This->swapchains[iSwapChain];
1921 IWineD3DSwapChain_AddRef(*pSwapChain);
1922 TRACE("(%p) returning %p\n", This, *pSwapChain);
1925 TRACE("Swapchain out of range\n");
1927 return WINED3DERR_INVALIDCALL;
1932 * Vertex Declaration
1934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1935 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1937 IWineD3DVertexDeclarationImpl *object = NULL;
1938 HRESULT hr = WINED3D_OK;
1940 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1941 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1943 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1946 ERR("Out of memory\n");
1947 *ppVertexDeclaration = NULL;
1948 return WINED3DERR_OUTOFVIDEOMEMORY;
1951 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1952 object->wineD3DDevice = This;
1953 object->parent = parent;
1956 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1958 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1960 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1961 *ppVertexDeclaration = NULL;
1967 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1968 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1970 unsigned int idx, idx2;
1971 unsigned int offset;
1972 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1973 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1974 BOOL has_blend_idx = has_blend &&
1975 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1976 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1977 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1978 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1979 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1980 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1981 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1983 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1984 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1986 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1987 WINED3DVERTEXELEMENT *elements = NULL;
1990 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1991 if (has_blend_idx) num_blends--;
1993 /* Compute declaration size */
1994 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1995 has_psize + has_diffuse + has_specular + num_textures + 1;
1997 /* convert the declaration */
1998 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2002 elements[size-1] = end_element;
2005 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2006 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2007 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
2009 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2010 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2011 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2014 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2015 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
2017 elements[idx].UsageIndex = 0;
2020 if (has_blend && (num_blends > 0)) {
2021 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2022 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2024 switch(num_blends) {
2025 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
2026 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
2027 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
2028 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
2030 ERR("Unexpected amount of blend values: %u\n", num_blends);
2033 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2034 elements[idx].UsageIndex = 0;
2037 if (has_blend_idx) {
2038 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2039 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2040 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
2041 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2042 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2044 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2045 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
2046 elements[idx].UsageIndex = 0;
2050 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2051 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
2052 elements[idx].UsageIndex = 0;
2056 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2057 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
2058 elements[idx].UsageIndex = 0;
2062 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2063 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2064 elements[idx].UsageIndex = 0;
2068 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
2069 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
2070 elements[idx].UsageIndex = 1;
2073 for (idx2 = 0; idx2 < num_textures; idx2++) {
2074 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2075 switch (numcoords) {
2076 case WINED3DFVF_TEXTUREFORMAT1:
2077 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
2079 case WINED3DFVF_TEXTUREFORMAT2:
2080 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
2082 case WINED3DFVF_TEXTUREFORMAT3:
2083 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
2085 case WINED3DFVF_TEXTUREFORMAT4:
2086 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
2089 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
2090 elements[idx].UsageIndex = idx2;
2094 /* Now compute offsets, and initialize the rest of the fields */
2095 for (idx = 0, offset = 0; idx < size-1; idx++) {
2096 elements[idx].Stream = 0;
2097 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
2098 elements[idx].Offset = offset;
2099 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
2102 *ppVertexElements = elements;
2106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2107 WINED3DVERTEXELEMENT* elements = NULL;
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2112 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2113 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
2115 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2116 HeapFree(GetProcessHeap(), 0, elements);
2117 if (hr != S_OK) return hr;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2124 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2125 HRESULT hr = WINED3D_OK;
2127 if (!pFunction) return WINED3DERR_INVALIDCALL;
2129 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2132 ERR("Out of memory\n");
2133 *ppVertexShader = NULL;
2134 return WINED3DERR_OUTOFVIDEOMEMORY;
2137 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2138 object->parent = parent;
2139 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2140 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2141 *ppVertexShader = (IWineD3DVertexShader *)object;
2143 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2145 if (vertex_declaration) {
2146 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2149 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2152 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2153 IWineD3DVertexShader_Release(*ppVertexShader);
2154 *ppVertexShader = NULL;
2161 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2163 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2164 HRESULT hr = WINED3D_OK;
2166 if (!pFunction) return WINED3DERR_INVALIDCALL;
2168 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2171 ERR("Out of memory\n");
2172 *ppPixelShader = NULL;
2173 return WINED3DERR_OUTOFVIDEOMEMORY;
2176 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2177 object->parent = parent;
2178 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2179 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2180 *ppPixelShader = (IWineD3DPixelShader *)object;
2182 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2184 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2187 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2188 IWineD3DPixelShader_Release(*ppPixelShader);
2189 *ppPixelShader = NULL;
2196 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2197 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2200 IWineD3DPaletteImpl *object;
2202 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2204 /* Create the new object */
2205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2207 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2208 return E_OUTOFMEMORY;
2211 object->lpVtbl = &IWineD3DPalette_Vtbl;
2213 object->Flags = Flags;
2214 object->parent = Parent;
2215 object->wineD3DDevice = This;
2216 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2217 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2220 HeapFree( GetProcessHeap(), 0, object);
2221 return E_OUTOFMEMORY;
2224 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2226 IWineD3DPalette_Release((IWineD3DPalette *) object);
2230 *Palette = (IWineD3DPalette *) object;
2235 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2239 HDC dcb = NULL, dcs = NULL;
2240 WINEDDCOLORKEY colorkey;
2242 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2245 GetObjectA(hbm, sizeof(BITMAP), &bm);
2246 dcb = CreateCompatibleDC(NULL);
2248 SelectObject(dcb, hbm);
2252 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2253 * couldn't be loaded
2255 memset(&bm, 0, sizeof(bm));
2260 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2261 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2262 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2264 ERR("Wine logo requested, but failed to create surface\n");
2269 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2270 if(FAILED(hr)) goto out;
2271 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2272 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2274 colorkey.dwColorSpaceLowValue = 0;
2275 colorkey.dwColorSpaceHighValue = 0;
2276 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2278 /* Fill the surface with a white color to show that wined3d is there */
2279 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2292 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2294 /* Under DirectX you can have texture stage operations even if no texture is
2295 bound, whereas opengl will only do texture operations when a valid texture is
2296 bound. We emulate this by creating dummy textures and binding them to each
2297 texture stage, but disable all stages by default. Hence if a stage is enabled
2298 then the default texture will kick in until replaced by a SetTexture call */
2301 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2302 /* The dummy texture does not have client storage backing */
2303 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2304 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2306 for (i = 0; i < GL_LIMITS(textures); i++) {
2307 GLubyte white = 255;
2309 /* Make appropriate texture active */
2310 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2311 checkGLcall("glActiveTextureARB");
2313 /* Generate an opengl texture name */
2314 glGenTextures(1, &This->dummyTextureName[i]);
2315 checkGLcall("glGenTextures");
2316 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2318 /* Generate a dummy 2d texture (not using 1d because they cause many
2319 * DRI drivers fall back to sw) */
2320 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2321 checkGLcall("glBindTexture");
2323 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2324 checkGLcall("glTexImage2D");
2326 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2327 /* Reenable because if supported it is enabled by default */
2328 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2329 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2335 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2336 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2339 IWineD3DSwapChainImpl *swapchain = NULL;
2344 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2346 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2347 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2349 /* TODO: Test if OpenGL is compiled in and loaded */
2351 TRACE("(%p) : Creating stateblock\n", This);
2352 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2353 hr = IWineD3DDevice_CreateStateBlock(iface,
2355 (IWineD3DStateBlock **)&This->stateBlock,
2357 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2358 WARN("Failed to create stateblock\n");
2361 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2362 This->updateStateBlock = This->stateBlock;
2363 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2365 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2366 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2368 This->NumberOfPalettes = 1;
2369 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2370 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2371 ERR("Out of memory!\n");
2374 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2375 if(!This->palettes[0]) {
2376 ERR("Out of memory!\n");
2379 for (i = 0; i < 256; ++i) {
2380 This->palettes[0][i].peRed = 0xFF;
2381 This->palettes[0][i].peGreen = 0xFF;
2382 This->palettes[0][i].peBlue = 0xFF;
2383 This->palettes[0][i].peFlags = 0xFF;
2385 This->currentPalette = 0;
2387 /* Initialize the texture unit mapping to a 1:1 mapping */
2388 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2389 if (state < GL_LIMITS(fragment_samplers)) {
2390 This->texUnitMap[state] = state;
2391 This->rev_tex_unit_map[state] = state;
2393 This->texUnitMap[state] = -1;
2394 This->rev_tex_unit_map[state] = -1;
2398 /* Setup the implicit swapchain */
2399 TRACE("Creating implicit swapchain\n");
2400 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2401 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2404 WARN("Failed to create implicit swapchain\n");
2408 This->NumberOfSwapChains = 1;
2409 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2410 if(!This->swapchains) {
2411 ERR("Out of memory!\n");
2414 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2416 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2417 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2418 This->render_targets[0] = swapchain->backBuffer[0];
2419 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2422 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2423 This->render_targets[0] = swapchain->frontBuffer;
2424 This->lastActiveRenderTarget = swapchain->frontBuffer;
2426 IWineD3DSurface_AddRef(This->render_targets[0]);
2427 This->activeContext = swapchain->context[0];
2428 This->lastThread = GetCurrentThreadId();
2430 /* Depth Stencil support */
2431 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2432 if (NULL != This->stencilBufferTarget) {
2433 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2436 hr = This->shader_backend->shader_alloc_private(iface);
2438 TRACE("Shader private data couldn't be allocated\n");
2441 hr = This->frag_pipe->alloc_private(iface);
2443 TRACE("Fragment pipeline private data couldn't be allocated\n");
2446 hr = This->blitter->alloc_private(iface);
2448 TRACE("Blitter private data couldn't be allocated\n");
2452 /* Set up some starting GL setup */
2454 /* Setup all the devices defaults */
2455 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2456 create_dummy_textures(This);
2460 /* Initialize the current view state */
2461 This->view_ident = 1;
2462 This->contexts[0]->last_was_rhw = 0;
2463 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2464 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2466 switch(wined3d_settings.offscreen_rendering_mode) {
2469 This->offscreenBuffer = GL_BACK;
2472 case ORM_BACKBUFFER:
2474 if(This->activeContext->aux_buffers > 0) {
2475 TRACE("Using auxilliary buffer for offscreen rendering\n");
2476 This->offscreenBuffer = GL_AUX0;
2478 TRACE("Using back buffer for offscreen rendering\n");
2479 This->offscreenBuffer = GL_BACK;
2484 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2487 /* Clear the screen */
2488 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2489 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2492 This->d3d_initialized = TRUE;
2494 if(wined3d_settings.logo) {
2495 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2497 This->highest_dirty_ps_const = 0;
2498 This->highest_dirty_vs_const = 0;
2502 HeapFree(GetProcessHeap(), 0, This->render_targets);
2503 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2504 HeapFree(GetProcessHeap(), 0, This->swapchains);
2505 This->NumberOfSwapChains = 0;
2506 if(This->palettes) {
2507 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2508 HeapFree(GetProcessHeap(), 0, This->palettes);
2510 This->NumberOfPalettes = 0;
2512 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2514 if(This->stateBlock) {
2515 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2516 This->stateBlock = NULL;
2518 if (This->blit_priv) {
2519 This->blitter->free_private(iface);
2521 if (This->fragment_priv) {
2522 This->frag_pipe->free_private(iface);
2524 if (This->shader_priv) {
2525 This->shader_backend->shader_free_private(iface);
2530 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2531 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2534 IWineD3DSwapChainImpl *swapchain = NULL;
2537 /* Setup the implicit swapchain */
2538 TRACE("Creating implicit swapchain\n");
2539 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2540 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2543 WARN("Failed to create implicit swapchain\n");
2547 This->NumberOfSwapChains = 1;
2548 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2549 if(!This->swapchains) {
2550 ERR("Out of memory!\n");
2553 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2557 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2561 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2563 IWineD3DResource_UnLoad(resource);
2564 IWineD3DResource_Release(resource);
2568 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2572 TRACE("(%p)\n", This);
2574 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2576 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2577 * it was created. Thus make sure a context is active for the glDelete* calls
2579 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2581 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2583 /* Unload resources */
2584 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2586 TRACE("Deleting high order patches\n");
2587 for(i = 0; i < PATCHMAP_SIZE; i++) {
2588 struct list *e1, *e2;
2589 struct WineD3DRectPatch *patch;
2590 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2591 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2592 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2596 /* Delete the palette conversion shader if it is around */
2597 if(This->paletteConversionShader) {
2599 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2601 This->paletteConversionShader = 0;
2604 /* Delete the pbuffer context if there is any */
2605 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2607 /* Delete the mouse cursor texture */
2608 if(This->cursorTexture) {
2610 glDeleteTextures(1, &This->cursorTexture);
2612 This->cursorTexture = 0;
2615 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2616 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2618 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2619 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2622 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2623 * private data, it might contain opengl pointers
2625 if(This->depth_blt_texture) {
2626 glDeleteTextures(1, &This->depth_blt_texture);
2627 This->depth_blt_texture = 0;
2629 if (This->depth_blt_rb) {
2630 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2631 This->depth_blt_rb = 0;
2632 This->depth_blt_rb_w = 0;
2633 This->depth_blt_rb_h = 0;
2636 /* Release the update stateblock */
2637 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2638 if(This->updateStateBlock != This->stateBlock)
2639 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2641 This->updateStateBlock = NULL;
2643 { /* because were not doing proper internal refcounts releasing the primary state block
2644 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2645 to set this->stateBlock = NULL; first */
2646 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2647 This->stateBlock = NULL;
2649 /* Release the stateblock */
2650 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2651 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2655 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2656 This->blitter->free_private(iface);
2657 This->frag_pipe->free_private(iface);
2658 This->shader_backend->shader_free_private(iface);
2660 /* Release the buffers (with sanity checks)*/
2661 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2662 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2663 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2664 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2666 This->stencilBufferTarget = NULL;
2668 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2669 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2670 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2672 TRACE("Setting rendertarget to NULL\n");
2673 This->render_targets[0] = NULL;
2675 if (This->auto_depth_stencil_buffer) {
2676 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2677 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2679 This->auto_depth_stencil_buffer = NULL;
2682 for(i=0; i < This->NumberOfSwapChains; i++) {
2683 TRACE("Releasing the implicit swapchain %d\n", i);
2684 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2685 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2689 HeapFree(GetProcessHeap(), 0, This->swapchains);
2690 This->swapchains = NULL;
2691 This->NumberOfSwapChains = 0;
2693 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2694 HeapFree(GetProcessHeap(), 0, This->palettes);
2695 This->palettes = NULL;
2696 This->NumberOfPalettes = 0;
2698 HeapFree(GetProcessHeap(), 0, This->render_targets);
2699 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2700 This->render_targets = NULL;
2701 This->draw_buffers = NULL;
2703 This->d3d_initialized = FALSE;
2707 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2711 for(i=0; i < This->NumberOfSwapChains; i++) {
2712 TRACE("Releasing the implicit swapchain %d\n", i);
2713 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2714 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2718 HeapFree(GetProcessHeap(), 0, This->swapchains);
2719 This->swapchains = NULL;
2720 This->NumberOfSwapChains = 0;
2724 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2725 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2726 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2728 * There is no way to deactivate thread safety once it is enabled.
2730 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2733 /*For now just store the flag(needed in case of ddraw) */
2734 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2740 const WINED3DDISPLAYMODE* pMode) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2744 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2747 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2749 /* Resize the screen even without a window:
2750 * The app could have unset it with SetCooperativeLevel, but not called
2751 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2752 * but we don't have any hwnd
2755 memset(&devmode, 0, sizeof(devmode));
2756 devmode.dmSize = sizeof(devmode);
2757 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2758 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2759 devmode.dmPelsWidth = pMode->Width;
2760 devmode.dmPelsHeight = pMode->Height;
2762 devmode.dmDisplayFrequency = pMode->RefreshRate;
2763 if (pMode->RefreshRate != 0) {
2764 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2767 /* Only change the mode if necessary */
2768 if( (This->ddraw_width == pMode->Width) &&
2769 (This->ddraw_height == pMode->Height) &&
2770 (This->ddraw_format == pMode->Format) &&
2771 (pMode->RefreshRate == 0) ) {
2775 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2776 if (ret != DISP_CHANGE_SUCCESSFUL) {
2777 if(devmode.dmDisplayFrequency != 0) {
2778 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2779 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2780 devmode.dmDisplayFrequency = 0;
2781 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2783 if(ret != DISP_CHANGE_SUCCESSFUL) {
2784 return WINED3DERR_NOTAVAILABLE;
2788 /* Store the new values */
2789 This->ddraw_width = pMode->Width;
2790 This->ddraw_height = pMode->Height;
2791 This->ddraw_format = pMode->Format;
2793 /* And finally clip mouse to our screen */
2794 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2795 ClipCursor(&clip_rc);
2800 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 *ppD3D= This->wineD3D;
2803 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2804 IWineD3D_AddRef(*ppD3D);
2808 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2812 (This->adapter->TextureRam/(1024*1024)),
2813 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2814 /* return simulated texture memory left */
2815 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2819 * Get / Set Stream Source
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2822 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2825 IWineD3DBuffer *oldSrc;
2827 if (StreamNumber >= MAX_STREAMS) {
2828 WARN("Stream out of range %d\n", StreamNumber);
2829 return WINED3DERR_INVALIDCALL;
2830 } else if(OffsetInBytes & 0x3) {
2831 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2832 return WINED3DERR_INVALIDCALL;
2835 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2836 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2838 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2840 if(oldSrc == pStreamData &&
2841 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2842 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2843 TRACE("Application is setting the old values over, nothing to do\n");
2847 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2849 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2850 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2853 /* Handle recording of state blocks */
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2856 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2857 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2861 if (pStreamData != NULL) {
2862 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2863 IWineD3DBuffer_AddRef(pStreamData);
2865 if (oldSrc != NULL) {
2866 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2867 IWineD3DBuffer_Release(oldSrc);
2870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2875 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2876 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2880 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2881 This->stateBlock->streamSource[StreamNumber],
2882 This->stateBlock->streamOffset[StreamNumber],
2883 This->stateBlock->streamStride[StreamNumber]);
2885 if (StreamNumber >= MAX_STREAMS) {
2886 WARN("Stream out of range %d\n", StreamNumber);
2887 return WINED3DERR_INVALIDCALL;
2889 *pStream = This->stateBlock->streamSource[StreamNumber];
2890 *pStride = This->stateBlock->streamStride[StreamNumber];
2892 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2895 if (*pStream != NULL) {
2896 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2904 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2906 /* Verify input at least in d3d9 this is invalid*/
2907 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2908 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2909 return WINED3DERR_INVALIDCALL;
2911 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2912 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2913 return WINED3DERR_INVALIDCALL;
2916 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2917 return WINED3DERR_INVALIDCALL;
2920 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2921 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2923 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2924 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2926 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2927 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2938 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2940 TRACE("(%p) : returning %d\n", This, *Divider);
2946 * Get / Set & Multiply Transform
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 /* Most of this routine, comments included copied from ddraw tree initially: */
2952 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2954 /* Handle recording of state blocks */
2955 if (This->isRecordingState) {
2956 TRACE("Recording... not performing anything\n");
2957 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2958 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2963 * If the new matrix is the same as the current one,
2964 * we cut off any further processing. this seems to be a reasonable
2965 * optimization because as was noticed, some apps (warcraft3 for example)
2966 * tend towards setting the same matrix repeatedly for some reason.
2968 * From here on we assume that the new matrix is different, wherever it matters.
2970 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2971 TRACE("The app is setting the same matrix over again\n");
2974 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2978 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2979 where ViewMat = Camera space, WorldMat = world space.
2981 In OpenGL, camera and world space is combined into GL_MODELVIEW
2982 matrix. The Projection matrix stay projection matrix.
2985 /* Capture the times we can just ignore the change for now */
2986 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2987 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2988 /* Handled by the state manager */
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2995 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2998 *pMatrix = This->stateBlock->transforms[State];
3002 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3003 const WINED3DMATRIX *mat = NULL;
3006 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3007 * below means it will be recorded in a state block change, but it
3008 * works regardless where it is recorded.
3009 * If this is found to be wrong, change to StateBlock.
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3014 if (State <= HIGHEST_TRANSFORMSTATE)
3016 mat = &This->updateStateBlock->transforms[State];
3018 FIXME("Unhandled transform state!!\n");
3021 multiply_matrix(&temp, mat, pMatrix);
3023 /* Apply change via set transform - will reapply to eg. lights this way */
3024 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3030 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3031 you can reference any indexes you want as long as that number max are enabled at any
3032 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3033 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3034 but when recording, just build a chain pretty much of commands to be replayed. */
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3038 PLIGHTINFOEL *object = NULL;
3039 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3045 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3049 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3050 return WINED3DERR_INVALIDCALL;
3053 switch(pLight->Type) {
3054 case WINED3DLIGHT_POINT:
3055 case WINED3DLIGHT_SPOT:
3056 case WINED3DLIGHT_PARALLELPOINT:
3057 case WINED3DLIGHT_GLSPOT:
3058 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3061 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3062 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3063 return WINED3DERR_INVALIDCALL;
3067 case WINED3DLIGHT_DIRECTIONAL:
3068 /* Ignores attenuation */
3072 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3073 return WINED3DERR_INVALIDCALL;
3076 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3077 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3078 if(object->OriginalIndex == Index) break;
3083 TRACE("Adding new light\n");
3084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3086 ERR("Out of memory error when allocating a light\n");
3087 return E_OUTOFMEMORY;
3089 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3090 object->glIndex = -1;
3091 object->OriginalIndex = Index;
3092 object->changed = TRUE;
3095 /* Initialize the object */
3096 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
3097 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3098 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3099 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3100 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3101 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3102 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3104 /* Save away the information */
3105 object->OriginalParms = *pLight;
3107 switch (pLight->Type) {
3108 case WINED3DLIGHT_POINT:
3110 object->lightPosn[0] = pLight->Position.x;
3111 object->lightPosn[1] = pLight->Position.y;
3112 object->lightPosn[2] = pLight->Position.z;
3113 object->lightPosn[3] = 1.0f;
3114 object->cutoff = 180.0f;
3118 case WINED3DLIGHT_DIRECTIONAL:
3120 object->lightPosn[0] = -pLight->Direction.x;
3121 object->lightPosn[1] = -pLight->Direction.y;
3122 object->lightPosn[2] = -pLight->Direction.z;
3123 object->lightPosn[3] = 0.0;
3124 object->exponent = 0.0f;
3125 object->cutoff = 180.0f;
3128 case WINED3DLIGHT_SPOT:
3130 object->lightPosn[0] = pLight->Position.x;
3131 object->lightPosn[1] = pLight->Position.y;
3132 object->lightPosn[2] = pLight->Position.z;
3133 object->lightPosn[3] = 1.0;
3136 object->lightDirn[0] = pLight->Direction.x;
3137 object->lightDirn[1] = pLight->Direction.y;
3138 object->lightDirn[2] = pLight->Direction.z;
3139 object->lightDirn[3] = 1.0;
3142 * opengl-ish and d3d-ish spot lights use too different models for the
3143 * light "intensity" as a function of the angle towards the main light direction,
3144 * so we only can approximate very roughly.
3145 * however spot lights are rather rarely used in games (if ever used at all).
3146 * furthermore if still used, probably nobody pays attention to such details.
3148 if (pLight->Falloff == 0) {
3149 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3150 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3151 * will always be 1.0 for both of them, and we don't have to care for the
3152 * rest of the rather complex calculation
3154 object->exponent = 0;
3156 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3157 if (rho < 0.0001) rho = 0.0001f;
3158 object->exponent = -0.3/log(cos(rho/2));
3160 if (object->exponent > 128.0) {
3161 object->exponent = 128.0;
3163 object->cutoff = pLight->Phi*90/M_PI;
3169 FIXME("Unrecognized light type %d\n", pLight->Type);
3172 /* Update the live definitions if the light is currently assigned a glIndex */
3173 if (object->glIndex != -1 && !This->isRecordingState) {
3174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3179 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3180 PLIGHTINFOEL *lightInfo = NULL;
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3184 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3186 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3187 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3188 if(lightInfo->OriginalIndex == Index) break;
3192 if (lightInfo == NULL) {
3193 TRACE("Light information requested but light not defined\n");
3194 return WINED3DERR_INVALIDCALL;
3197 *pLight = lightInfo->OriginalParms;
3202 * Get / Set Light Enable
3203 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3206 PLIGHTINFOEL *lightInfo = NULL;
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3210 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3212 /* Tests show true = 128...not clear why */
3213 Enable = Enable? 128: 0;
3215 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3216 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3217 if(lightInfo->OriginalIndex == Index) break;
3220 TRACE("Found light: %p\n", lightInfo);
3222 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3223 if (lightInfo == NULL) {
3225 TRACE("Light enabled requested but light not defined, so defining one!\n");
3226 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3228 /* Search for it again! Should be fairly quick as near head of list */
3229 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3230 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3231 if(lightInfo->OriginalIndex == Index) break;
3234 if (lightInfo == NULL) {
3235 FIXME("Adding default lights has failed dismally\n");
3236 return WINED3DERR_INVALIDCALL;
3240 lightInfo->enabledChanged = TRUE;
3242 if(lightInfo->glIndex != -1) {
3243 if(!This->isRecordingState) {
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3247 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3248 lightInfo->glIndex = -1;
3250 TRACE("Light already disabled, nothing to do\n");
3252 lightInfo->enabled = FALSE;
3254 lightInfo->enabled = TRUE;
3255 if (lightInfo->glIndex != -1) {
3257 TRACE("Nothing to do as light was enabled\n");
3260 /* Find a free gl light */
3261 for(i = 0; i < This->maxConcurrentLights; i++) {
3262 if(This->updateStateBlock->activeLights[i] == NULL) {
3263 This->updateStateBlock->activeLights[i] = lightInfo;
3264 lightInfo->glIndex = i;
3268 if(lightInfo->glIndex == -1) {
3269 /* Our tests show that Windows returns D3D_OK in this situation, even with
3270 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3271 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3272 * as well for those lights.
3274 * TODO: Test how this affects rendering
3276 WARN("Too many concurrently active lights\n");
3280 /* i == lightInfo->glIndex */
3281 if(!This->isRecordingState) {
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3292 PLIGHTINFOEL *lightInfo = NULL;
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3296 TRACE("(%p) : for idx(%d)\n", This, Index);
3298 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3299 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3300 if(lightInfo->OriginalIndex == Index) break;
3304 if (lightInfo == NULL) {
3305 TRACE("Light enabled state requested but light not defined\n");
3306 return WINED3DERR_INVALIDCALL;
3308 /* true is 128 according to SetLightEnable */
3309 *pEnable = lightInfo->enabled ? 128 : 0;
3314 * Get / Set Clip Planes
3316 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3320 /* Validate Index */
3321 if (Index >= GL_LIMITS(clipplanes)) {
3322 TRACE("Application has requested clipplane this device doesn't support\n");
3323 return WINED3DERR_INVALIDCALL;
3326 This->updateStateBlock->changed.clipplane |= 1 << Index;
3328 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3329 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3330 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3331 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3332 TRACE("Application is setting old values over, nothing to do\n");
3336 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3337 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3338 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3339 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3341 /* Handle recording of state blocks */
3342 if (This->isRecordingState) {
3343 TRACE("Recording... not performing anything\n");
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 TRACE("(%p) : for idx %d\n", This, Index);
3356 /* Validate Index */
3357 if (Index >= GL_LIMITS(clipplanes)) {
3358 TRACE("Application has requested clipplane this device doesn't support\n");
3359 return WINED3DERR_INVALIDCALL;
3362 pPlane[0] = This->stateBlock->clipplane[Index][0];
3363 pPlane[1] = This->stateBlock->clipplane[Index][1];
3364 pPlane[2] = This->stateBlock->clipplane[Index][2];
3365 pPlane[3] = This->stateBlock->clipplane[Index][3];
3370 * Get / Set Clip Plane Status
3371 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 FIXME("(%p) : stub\n", This);
3376 if (NULL == pClipStatus) {
3377 return WINED3DERR_INVALIDCALL;
3379 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3380 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 FIXME("(%p) : stub\n", This);
3387 if (NULL == pClipStatus) {
3388 return WINED3DERR_INVALIDCALL;
3390 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3391 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3396 * Get / Set Material
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 This->updateStateBlock->changed.material = TRUE;
3402 This->updateStateBlock->material = *pMaterial;
3404 /* Handle recording of state blocks */
3405 if (This->isRecordingState) {
3406 TRACE("Recording... not performing anything\n");
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 *pMaterial = This->updateStateBlock->material;
3417 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3418 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3419 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3420 pMaterial->Ambient.b, pMaterial->Ambient.a);
3421 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3422 pMaterial->Specular.b, pMaterial->Specular.a);
3423 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3424 pMaterial->Emissive.b, pMaterial->Emissive.a);
3425 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 IWineD3DIndexBuffer *oldIdxs;
3437 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3438 oldIdxs = This->updateStateBlock->pIndexData;
3440 This->updateStateBlock->changed.indices = TRUE;
3441 This->updateStateBlock->pIndexData = pIndexData;
3443 /* Handle recording of state blocks */
3444 if (This->isRecordingState) {
3445 TRACE("Recording... not performing anything\n");
3446 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3447 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3451 if(oldIdxs != pIndexData) {
3452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3453 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3454 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3459 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 *ppIndexData = This->stateBlock->pIndexData;
3464 /* up ref count on ppindexdata */
3466 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3467 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3469 TRACE("(%p) No index data set\n", This);
3471 TRACE("Returning %p\n", *ppIndexData);
3476 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 TRACE("(%p)->(%d)\n", This, BaseIndex);
3481 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3482 TRACE("Application is setting the old value over, nothing to do\n");
3486 This->updateStateBlock->baseVertexIndex = BaseIndex;
3488 if (This->isRecordingState) {
3489 TRACE("Recording... not performing anything\n");
3492 /* The base vertex index affects the stream sources */
3493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3497 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 TRACE("(%p) : base_index %p\n", This, base_index);
3501 *base_index = This->stateBlock->baseVertexIndex;
3503 TRACE("Returning %u\n", *base_index);
3509 * Get / Set Viewports
3511 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 TRACE("(%p)\n", This);
3515 This->updateStateBlock->changed.viewport = TRUE;
3516 This->updateStateBlock->viewport = *pViewport;
3518 /* Handle recording of state blocks */
3519 if (This->isRecordingState) {
3520 TRACE("Recording... not performing anything\n");
3524 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3525 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 TRACE("(%p)\n", This);
3535 *pViewport = This->stateBlock->viewport;
3540 * Get / Set Render States
3541 * TODO: Verify against dx9 definitions
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 DWORD oldValue = This->stateBlock->renderState[State];
3548 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3550 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3551 This->updateStateBlock->renderState[State] = Value;
3553 /* Handle recording of state blocks */
3554 if (This->isRecordingState) {
3555 TRACE("Recording... not performing anything\n");
3559 /* Compared here and not before the assignment to allow proper stateblock recording */
3560 if(Value == oldValue) {
3561 TRACE("Application is setting the old value over, nothing to do\n");
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3569 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3572 *pValue = This->stateBlock->renderState[State];
3577 * Get / Set Sampler States
3578 * TODO: Verify against dx9 definitions
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3586 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3588 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3589 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3592 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3593 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3594 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3597 * SetSampler is designed to allow for more than the standard up to 8 textures
3598 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3599 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3601 * http://developer.nvidia.com/object/General_FAQ.html#t6
3603 * There are two new settings for GForce
3605 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3606 * and the texture one:
3607 * GL_MAX_TEXTURE_COORDS_ARB.
3608 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3611 oldValue = This->stateBlock->samplerState[Sampler][Type];
3612 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3613 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3615 /* Handle recording of state blocks */
3616 if (This->isRecordingState) {
3617 TRACE("Recording... not performing anything\n");
3621 if(oldValue == Value) {
3622 TRACE("Application is setting the old value over, nothing to do\n");
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3631 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3634 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3635 This, Sampler, debug_d3dsamplerstate(Type), Type);
3637 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3638 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3641 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3642 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3643 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3645 *Value = This->stateBlock->samplerState[Sampler][Type];
3646 TRACE("(%p) : Returning %#x\n", This, *Value);
3651 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654 This->updateStateBlock->changed.scissorRect = TRUE;
3655 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3656 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3659 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3661 if(This->isRecordingState) {
3662 TRACE("Recording... not performing anything\n");
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3671 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3674 *pRect = This->updateStateBlock->scissorRect;
3675 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3679 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3681 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3683 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3685 This->updateStateBlock->vertexDecl = pDecl;
3686 This->updateStateBlock->changed.vertexDecl = TRUE;
3688 if (This->isRecordingState) {
3689 TRACE("Recording... not performing anything\n");
3691 } else if(pDecl == oldDecl) {
3692 /* Checked after the assignment to allow proper stateblock recording */
3693 TRACE("Application is setting the old declaration over, nothing to do\n");
3697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3701 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3706 *ppDecl = This->stateBlock->vertexDecl;
3707 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3713 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3715 This->updateStateBlock->vertexShader = pShader;
3716 This->updateStateBlock->changed.vertexShader = TRUE;
3718 if (This->isRecordingState) {
3719 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3720 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3721 TRACE("Recording... not performing anything\n");
3723 } else if(oldShader == pShader) {
3724 /* Checked here to allow proper stateblock recording */
3725 TRACE("App is setting the old shader over, nothing to do\n");
3729 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3730 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3731 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 if (NULL == ppShader) {
3742 return WINED3DERR_INVALIDCALL;
3744 *ppShader = This->stateBlock->vertexShader;
3745 if( NULL != *ppShader)
3746 IWineD3DVertexShader_AddRef(*ppShader);
3748 TRACE("(%p) : returning %p\n", This, *ppShader);
3752 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3753 IWineD3DDevice *iface,
3755 CONST BOOL *srcData,
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3761 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3762 iface, srcData, start, count);
3764 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3766 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3767 for (i = 0; i < cnt; i++)
3768 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3770 for (i = start; i < cnt + start; ++i) {
3771 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3774 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3779 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3780 IWineD3DDevice *iface,
3785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3786 int cnt = min(count, MAX_CONST_B - start);
3788 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3789 iface, dstData, start, count);
3791 if (dstData == NULL || cnt < 0)
3792 return WINED3DERR_INVALIDCALL;
3794 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3798 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3799 IWineD3DDevice *iface,
3804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3805 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3807 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3808 iface, srcData, start, count);
3810 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3812 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3813 for (i = 0; i < cnt; i++)
3814 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3815 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3817 for (i = start; i < cnt + start; ++i) {
3818 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3821 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3826 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3827 IWineD3DDevice *iface,
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 int cnt = min(count, MAX_CONST_I - start);
3835 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3836 iface, dstData, start, count);
3838 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3839 return WINED3DERR_INVALIDCALL;
3841 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3845 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3846 IWineD3DDevice *iface,
3848 CONST float *srcData,
3851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3855 iface, srcData, start, count);
3857 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3858 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3859 return WINED3DERR_INVALIDCALL;
3861 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3863 for (i = 0; i < count; i++)
3864 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3865 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3868 if (!This->isRecordingState)
3870 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3874 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3875 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3880 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3881 IWineD3DDevice *iface,
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3889 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3890 iface, dstData, start, count);
3892 if (dstData == NULL || cnt < 0)
3893 return WINED3DERR_INVALIDCALL;
3895 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3899 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3901 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3907 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3908 int i = This->rev_tex_unit_map[unit];
3909 int j = This->texUnitMap[stage];
3911 This->texUnitMap[stage] = unit;
3912 if (i != -1 && i != stage) {
3913 This->texUnitMap[i] = -1;
3916 This->rev_tex_unit_map[unit] = stage;
3917 if (j != -1 && j != unit) {
3918 This->rev_tex_unit_map[j] = -1;
3922 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3925 This->fixed_function_usage_map = 0;
3926 for (i = 0; i < MAX_TEXTURES; ++i) {
3927 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3928 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3929 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3930 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3931 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3932 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3933 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3934 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3936 if (color_op == WINED3DTOP_DISABLE) {
3937 /* Not used, and disable higher stages */
3941 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3942 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3943 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3944 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3945 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3946 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3947 This->fixed_function_usage_map |= (1 << i);
3950 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3951 This->fixed_function_usage_map |= (1 << (i + 1));
3956 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3957 unsigned int i, tex;
3960 device_update_fixed_function_usage_map(This);
3961 ffu_map = This->fixed_function_usage_map;
3963 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3964 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3965 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3967 if (!(ffu_map & 1)) continue;
3969 if (This->texUnitMap[i] != i) {
3970 device_map_stage(This, i, i);
3971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3972 markTextureStagesDirty(This, i);
3978 /* Now work out the mapping */
3980 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3982 if (!(ffu_map & 1)) continue;
3984 if (This->texUnitMap[i] != tex) {
3985 device_map_stage(This, i, tex);
3986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3987 markTextureStagesDirty(This, i);
3994 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3995 const DWORD *sampler_tokens =
3996 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3999 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4000 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4001 device_map_stage(This, i, i);
4002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4003 if (i < MAX_TEXTURES) {
4004 markTextureStagesDirty(This, i);
4010 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4011 const DWORD *vshader_sampler_tokens, int unit)
4013 int current_mapping = This->rev_tex_unit_map[unit];
4015 if (current_mapping == -1) {
4016 /* Not currently used */
4020 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4021 /* Used by a fragment sampler */
4023 if (!pshader_sampler_tokens) {
4024 /* No pixel shader, check fixed function */
4025 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4028 /* Pixel shader, check the shader's sampler map */
4029 return !pshader_sampler_tokens[current_mapping];
4032 /* Used by a vertex sampler */
4033 return !vshader_sampler_tokens[current_mapping];
4036 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4037 const DWORD *vshader_sampler_tokens =
4038 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4039 const DWORD *pshader_sampler_tokens = NULL;
4040 int start = GL_LIMITS(combined_samplers) - 1;
4044 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4046 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4047 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4048 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4051 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4052 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4053 if (vshader_sampler_tokens[i]) {
4054 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4056 /* Already mapped somewhere */
4060 while (start >= 0) {
4061 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4062 device_map_stage(This, vsampler_idx, start);
4063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4075 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4076 BOOL vs = use_vs(This->stateBlock);
4077 BOOL ps = use_ps(This->stateBlock);
4080 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4081 * that would be really messy and require shader recompilation
4082 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4083 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4086 device_map_psamplers(This);
4088 device_map_fixed_function_samplers(This);
4092 device_map_vsamplers(This, ps);
4096 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4098 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4099 This->updateStateBlock->pixelShader = pShader;
4100 This->updateStateBlock->changed.pixelShader = TRUE;
4102 /* Handle recording of state blocks */
4103 if (This->isRecordingState) {
4104 TRACE("Recording... not performing anything\n");
4107 if (This->isRecordingState) {
4108 TRACE("Recording... not performing anything\n");
4109 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4110 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4114 if(pShader == oldShader) {
4115 TRACE("App is setting the old pixel shader over, nothing to do\n");
4119 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4120 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4122 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4128 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4131 if (NULL == ppShader) {
4132 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4133 return WINED3DERR_INVALIDCALL;
4136 *ppShader = This->stateBlock->pixelShader;
4137 if (NULL != *ppShader) {
4138 IWineD3DPixelShader_AddRef(*ppShader);
4140 TRACE("(%p) : returning %p\n", This, *ppShader);
4144 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4145 IWineD3DDevice *iface,
4147 CONST BOOL *srcData,
4150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4151 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4153 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4154 iface, srcData, start, count);
4156 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4158 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4159 for (i = 0; i < cnt; i++)
4160 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4162 for (i = start; i < cnt + start; ++i) {
4163 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4166 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4171 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4172 IWineD3DDevice *iface,
4177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4178 int cnt = min(count, MAX_CONST_B - start);
4180 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4181 iface, dstData, start, count);
4183 if (dstData == NULL || cnt < 0)
4184 return WINED3DERR_INVALIDCALL;
4186 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4190 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4191 IWineD3DDevice *iface,
4196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4199 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4200 iface, srcData, start, count);
4202 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4204 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4205 for (i = 0; i < cnt; i++)
4206 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4207 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4209 for (i = start; i < cnt + start; ++i) {
4210 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4213 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4218 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4219 IWineD3DDevice *iface,
4224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4225 int cnt = min(count, MAX_CONST_I - start);
4227 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4228 iface, dstData, start, count);
4230 if (dstData == NULL || cnt < 0)
4231 return WINED3DERR_INVALIDCALL;
4233 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4237 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4238 IWineD3DDevice *iface,
4240 CONST float *srcData,
4243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4246 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4247 iface, srcData, start, count);
4249 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4250 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4251 return WINED3DERR_INVALIDCALL;
4253 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4255 for (i = 0; i < count; i++)
4256 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4257 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4260 if (!This->isRecordingState)
4262 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4266 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4267 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4272 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4273 IWineD3DDevice *iface,
4278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4279 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4281 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4282 iface, dstData, start, count);
4284 if (dstData == NULL || cnt < 0)
4285 return WINED3DERR_INVALIDCALL;
4287 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4291 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4292 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4293 const WineDirect3DVertexStridedData *lpStrideData, struct wined3d_buffer *dest, DWORD dwFlags)
4295 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4297 DWORD DestFVF = dest->fvf;
4299 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4303 if (lpStrideData->u.s.normal.lpData) {
4304 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4307 if (lpStrideData->u.s.position.lpData == NULL) {
4308 ERR("Source has no position mask\n");
4309 return WINED3DERR_INVALIDCALL;
4312 /* We might access VBOs from this code, so hold the lock */
4315 if (dest->resource.allocatedMemory == NULL) {
4316 /* This may happen if we do direct locking into a vbo. Unlikely,
4317 * but theoretically possible(ddraw processvertices test)
4319 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4320 if(!dest->resource.allocatedMemory) {
4322 ERR("Out of memory\n");
4323 return E_OUTOFMEMORY;
4325 if (dest->buffer_object)
4328 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4329 checkGLcall("glBindBufferARB");
4330 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4332 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4334 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4335 checkGLcall("glUnmapBufferARB");
4339 /* Get a pointer into the destination vbo(create one if none exists) and
4340 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4342 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4344 dest->flags |= WINED3D_BUFFER_CREATEBO;
4345 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4348 if (dest->buffer_object)
4350 unsigned char extrabytes = 0;
4351 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4352 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4353 * this may write 4 extra bytes beyond the area that should be written
4355 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4356 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4357 if(!dest_conv_addr) {
4358 ERR("Out of memory\n");
4359 /* Continue without storing converted vertices */
4361 dest_conv = dest_conv_addr;
4365 * a) WINED3DRS_CLIPPING is enabled
4366 * b) WINED3DVOP_CLIP is passed
4368 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4369 static BOOL warned = FALSE;
4371 * The clipping code is not quite correct. Some things need
4372 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4373 * so disable clipping for now.
4374 * (The graphics in Half-Life are broken, and my processvertices
4375 * test crashes with IDirect3DDevice3)
4381 FIXME("Clipping is broken and disabled for now\n");
4383 } else doClip = FALSE;
4384 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4386 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4389 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4390 WINED3DTS_PROJECTION,
4392 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4393 WINED3DTS_WORLDMATRIX(0),
4396 TRACE("View mat:\n");
4397 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);
4398 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);
4399 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);
4400 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);
4402 TRACE("Proj mat:\n");
4403 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);
4404 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);
4405 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);
4406 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);
4408 TRACE("World mat:\n");
4409 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);
4410 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);
4411 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);
4412 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);
4414 /* Get the viewport */
4415 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4416 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4417 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4419 multiply_matrix(&mat,&view_mat,&world_mat);
4420 multiply_matrix(&mat,&proj_mat,&mat);
4422 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4424 for (i = 0; i < dwCount; i+= 1) {
4425 unsigned int tex_index;
4427 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4428 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4429 /* The position first */
4431 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4433 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4435 /* Multiplication with world, view and projection matrix */
4436 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);
4437 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);
4438 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);
4439 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);
4441 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4443 /* WARNING: The following things are taken from d3d7 and were not yet checked
4444 * against d3d8 or d3d9!
4447 /* Clipping conditions: From msdn
4449 * A vertex is clipped if it does not match the following requirements
4453 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4455 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4456 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4461 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4462 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4465 /* "Normal" viewport transformation (not clipped)
4466 * 1) The values are divided by rhw
4467 * 2) The y axis is negative, so multiply it with -1
4468 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4469 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4470 * 4) Multiply x with Width/2 and add Width/2
4471 * 5) The same for the height
4472 * 6) Add the viewpoint X and Y to the 2D coordinates and
4473 * The minimum Z value to z
4474 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4476 * Well, basically it's simply a linear transformation into viewport
4488 z *= vp.MaxZ - vp.MinZ;
4490 x += vp.Width / 2 + vp.X;
4491 y += vp.Height / 2 + vp.Y;
4496 /* That vertex got clipped
4497 * Contrary to OpenGL it is not dropped completely, it just
4498 * undergoes a different calculation.
4500 TRACE("Vertex got clipped\n");
4507 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4508 * outside of the main vertex buffer memory. That needs some more
4513 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4516 ( (float *) dest_ptr)[0] = x;
4517 ( (float *) dest_ptr)[1] = y;
4518 ( (float *) dest_ptr)[2] = z;
4519 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4521 dest_ptr += 3 * sizeof(float);
4523 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4524 dest_ptr += sizeof(float);
4529 ( (float *) dest_conv)[0] = x * w;
4530 ( (float *) dest_conv)[1] = y * w;
4531 ( (float *) dest_conv)[2] = z * w;
4532 ( (float *) dest_conv)[3] = w;
4534 dest_conv += 3 * sizeof(float);
4536 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4537 dest_conv += sizeof(float);
4541 if (DestFVF & WINED3DFVF_PSIZE) {
4542 dest_ptr += sizeof(DWORD);
4543 if(dest_conv) dest_conv += sizeof(DWORD);
4545 if (DestFVF & WINED3DFVF_NORMAL) {
4546 const float *normal =
4547 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4548 /* AFAIK this should go into the lighting information */
4549 FIXME("Didn't expect the destination to have a normal\n");
4550 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4552 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4556 if (DestFVF & WINED3DFVF_DIFFUSE) {
4557 const DWORD *color_d =
4558 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4560 static BOOL warned = FALSE;
4563 ERR("No diffuse color in source, but destination has one\n");
4567 *( (DWORD *) dest_ptr) = 0xffffffff;
4568 dest_ptr += sizeof(DWORD);
4571 *( (DWORD *) dest_conv) = 0xffffffff;
4572 dest_conv += sizeof(DWORD);
4576 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4578 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4579 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4580 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4581 dest_conv += sizeof(DWORD);
4586 if (DestFVF & WINED3DFVF_SPECULAR) {
4587 /* What's the color value in the feedback buffer? */
4588 const DWORD *color_s =
4589 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4591 static BOOL warned = FALSE;
4594 ERR("No specular color in source, but destination has one\n");
4598 *( (DWORD *) dest_ptr) = 0xFF000000;
4599 dest_ptr += sizeof(DWORD);
4602 *( (DWORD *) dest_conv) = 0xFF000000;
4603 dest_conv += sizeof(DWORD);
4607 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4609 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4610 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4611 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4612 dest_conv += sizeof(DWORD);
4617 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4618 const float *tex_coord =
4619 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4620 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4622 ERR("No source texture, but destination requests one\n");
4623 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4624 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4627 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4629 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4636 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4637 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4638 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4639 dwCount * get_flexible_vertex_size(DestFVF),
4641 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4642 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4649 #undef copy_and_next
4651 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4652 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 WineDirect3DVertexStridedData strided;
4656 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4657 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4660 ERR("Output vertex declaration not implemented yet\n");
4663 /* Need any context to write to the vbo. */
4664 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4666 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4667 * control the streamIsUP flag, thus restore it afterwards.
4669 This->stateBlock->streamIsUP = FALSE;
4670 memset(&strided, 0, sizeof(strided));
4671 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4672 This->stateBlock->streamIsUP = streamWasUP;
4674 if(vbo || SrcStartIndex) {
4676 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4677 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4679 * Also get the start index in, but only loop over all elements if there's something to add at all.
4681 #define FIXSRC(type) \
4682 if(strided.u.s.type.VBO) { \
4683 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4684 strided.u.s.type.VBO = 0; \
4685 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4687 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); \
4688 vb->buffer_object = 0; \
4691 if(strided.u.s.type.lpData) { \
4692 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4695 FIXSRC(blendWeights);
4696 FIXSRC(blendMatrixIndices);
4701 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4702 FIXSRC(texCoords[i]);
4715 return process_vertices_strided(This, DestIndex, VertexCount, &strided,
4716 (struct wined3d_buffer *)pDestBuffer, Flags);
4720 * Get / Set Texture Stage States
4721 * TODO: Verify against dx9 definitions
4723 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4727 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4729 if (Stage >= MAX_TEXTURES) {
4730 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4734 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4735 This->updateStateBlock->textureState[Stage][Type] = Value;
4737 if (This->isRecordingState) {
4738 TRACE("Recording... not performing anything\n");
4742 /* Checked after the assignments to allow proper stateblock recording */
4743 if(oldValue == Value) {
4744 TRACE("App is setting the old value over, nothing to do\n");
4748 if(Stage > This->stateBlock->lowest_disabled_stage &&
4749 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4750 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4751 * Changes in other states are important on disabled stages too
4756 if(Type == WINED3DTSS_COLOROP) {
4759 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4760 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4761 * they have to be disabled
4763 * The current stage is dirtified below.
4765 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4766 TRACE("Additionally dirtifying stage %u\n", i);
4767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4769 This->stateBlock->lowest_disabled_stage = Stage;
4770 TRACE("New lowest disabled: %u\n", Stage);
4771 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4772 /* Previously disabled stage enabled. Stages above it may need enabling
4773 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4774 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4776 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4779 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4780 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4783 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4786 This->stateBlock->lowest_disabled_stage = i;
4787 TRACE("New lowest disabled: %u\n", i);
4791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4796 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4799 *pValue = This->updateStateBlock->textureState[Stage][Type];
4806 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 IWineD3DBaseTexture *oldTexture;
4810 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4812 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4813 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4816 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4817 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4818 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4821 oldTexture = This->updateStateBlock->textures[Stage];
4823 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4824 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4826 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4827 return WINED3DERR_INVALIDCALL;
4830 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4831 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4833 This->updateStateBlock->changed.textures |= 1 << Stage;
4834 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4835 This->updateStateBlock->textures[Stage] = pTexture;
4837 /* Handle recording of state blocks */
4838 if (This->isRecordingState) {
4839 TRACE("Recording... not performing anything\n");
4843 if(oldTexture == pTexture) {
4844 TRACE("App is setting the same texture again, nothing to do\n");
4848 /** NOTE: MSDN says that setTexture increases the reference count,
4849 * and that the application must set the texture back to null (or have a leaky application),
4850 * This means we should pass the refcount up to the parent
4851 *******************************/
4852 if (NULL != This->updateStateBlock->textures[Stage]) {
4853 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4854 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4855 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4857 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4859 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4864 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4865 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4866 * so the COLOROP and ALPHAOP have to be dirtified.
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4871 if(bindCount == 1) {
4872 new->baseTexture.sampler = Stage;
4874 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4878 if (NULL != oldTexture) {
4879 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4880 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4882 IWineD3DBaseTexture_Release(oldTexture);
4883 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4888 if(bindCount && old->baseTexture.sampler == Stage) {
4890 /* Have to do a search for the other sampler(s) where the texture is bound to
4891 * Shouldn't happen as long as apps bind a texture only to one stage
4893 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4894 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4895 if(This->updateStateBlock->textures[i] == oldTexture) {
4896 old->baseTexture.sampler = i;
4903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4908 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4913 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4914 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4917 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4918 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4919 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4922 *ppTexture=This->stateBlock->textures[Stage];
4924 IWineD3DBaseTexture_AddRef(*ppTexture);
4926 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4934 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4935 IWineD3DSurface **ppBackBuffer) {
4936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4937 IWineD3DSwapChain *swapChain;
4940 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4942 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4943 if (hr == WINED3D_OK) {
4944 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4945 IWineD3DSwapChain_Release(swapChain);
4947 *ppBackBuffer = NULL;
4952 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 WARN("(%p) : stub, calling idirect3d for now\n", This);
4955 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4958 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 IWineD3DSwapChain *swapChain;
4963 if(iSwapChain > 0) {
4964 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4965 if (hr == WINED3D_OK) {
4966 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4967 IWineD3DSwapChain_Release(swapChain);
4969 FIXME("(%p) Error getting display mode\n", This);
4972 /* Don't read the real display mode,
4973 but return the stored mode instead. X11 can't change the color
4974 depth, and some apps are pretty angry if they SetDisplayMode from
4975 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4977 Also don't relay to the swapchain because with ddraw it's possible
4978 that there isn't a swapchain at all */
4979 pMode->Width = This->ddraw_width;
4980 pMode->Height = This->ddraw_height;
4981 pMode->Format = This->ddraw_format;
4982 pMode->RefreshRate = 0;
4990 * Stateblock related functions
4993 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 IWineD3DStateBlock *stateblock;
4998 TRACE("(%p)\n", This);
5000 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5002 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5003 if (FAILED(hr)) return hr;
5005 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5006 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5007 This->isRecordingState = TRUE;
5009 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5014 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5017 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5019 if (!This->isRecordingState) {
5020 WARN("(%p) not recording! returning error\n", This);
5021 *ppStateBlock = NULL;
5022 return WINED3DERR_INVALIDCALL;
5025 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5027 DWORD map = object->changed.renderState[i];
5028 for (j = 0; map; map >>= 1, ++j)
5030 if (!(map & 1)) continue;
5032 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5036 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5038 DWORD map = object->changed.transform[i];
5039 for (j = 0; map; map >>= 1, ++j)
5041 if (!(map & 1)) continue;
5043 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5046 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5047 if(object->changed.vertexShaderConstantsF[i]) {
5048 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5049 object->num_contained_vs_consts_f++;
5052 for(i = 0; i < MAX_CONST_I; i++) {
5053 if (object->changed.vertexShaderConstantsI & (1 << i))
5055 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5056 object->num_contained_vs_consts_i++;
5059 for(i = 0; i < MAX_CONST_B; i++) {
5060 if (object->changed.vertexShaderConstantsB & (1 << i))
5062 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5063 object->num_contained_vs_consts_b++;
5066 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5068 if (object->changed.pixelShaderConstantsF[i])
5070 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5071 ++object->num_contained_ps_consts_f;
5074 for(i = 0; i < MAX_CONST_I; i++) {
5075 if (object->changed.pixelShaderConstantsI & (1 << i))
5077 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5078 object->num_contained_ps_consts_i++;
5081 for(i = 0; i < MAX_CONST_B; i++) {
5082 if (object->changed.pixelShaderConstantsB & (1 << i))
5084 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5085 object->num_contained_ps_consts_b++;
5088 for(i = 0; i < MAX_TEXTURES; i++) {
5089 DWORD map = object->changed.textureState[i];
5091 for(j = 0; map; map >>= 1, ++j)
5093 if (!(map & 1)) continue;
5095 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5096 object->contained_tss_states[object->num_contained_tss_states].state = j;
5097 ++object->num_contained_tss_states;
5100 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5101 DWORD map = object->changed.samplerState[i];
5103 for (j = 0; map; map >>= 1, ++j)
5105 if (!(map & 1)) continue;
5107 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5108 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5109 ++object->num_contained_sampler_states;
5113 *ppStateBlock = (IWineD3DStateBlock*) object;
5114 This->isRecordingState = FALSE;
5115 This->updateStateBlock = This->stateBlock;
5116 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5117 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5118 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5123 * Scene related functions
5125 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5126 /* At the moment we have no need for any functionality at the beginning
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 TRACE("(%p)\n", This);
5132 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5133 return WINED3DERR_INVALIDCALL;
5135 This->inScene = TRUE;
5139 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5141 TRACE("(%p)\n", This);
5143 if(!This->inScene) {
5144 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5145 return WINED3DERR_INVALIDCALL;
5148 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5149 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5151 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5155 This->inScene = FALSE;
5159 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5160 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5161 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 IWineD3DSwapChain *swapChain = NULL;
5165 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5167 TRACE("(%p) Presenting the frame\n", This);
5169 for(i = 0 ; i < swapchains ; i ++) {
5171 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5172 TRACE("presentinng chain %d, %p\n", i, swapChain);
5173 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5174 IWineD3DSwapChain_Release(swapChain);
5180 /* Not called from the VTable (internal subroutine) */
5181 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5182 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5183 float Z, DWORD Stencil) {
5184 GLbitfield glMask = 0;
5186 WINED3DRECT curRect;
5188 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5189 UINT drawable_width, drawable_height;
5190 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5191 IWineD3DSwapChainImpl *swapchain = NULL;
5193 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5194 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5195 * for the cleared parts, and the untouched parts.
5197 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5198 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5199 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5200 * checking all this if the dest surface is in the drawable anyway.
5202 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5204 if(vp->X != 0 || vp->Y != 0 ||
5205 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5206 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5209 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5210 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5211 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5212 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5213 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5216 if(Count > 0 && pRects && (
5217 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5218 pRects[0].x2 < target->currentDesc.Width ||
5219 pRects[0].y2 < target->currentDesc.Height)) {
5220 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5227 target->get_drawable_size(target, &drawable_width, &drawable_height);
5229 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5232 /* Only set the values up once, as they are not changing */
5233 if (Flags & WINED3DCLEAR_STENCIL) {
5234 glClearStencil(Stencil);
5235 checkGLcall("glClearStencil");
5236 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5237 glStencilMask(0xFFFFFFFF);
5240 if (Flags & WINED3DCLEAR_ZBUFFER) {
5241 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5242 glDepthMask(GL_TRUE);
5244 checkGLcall("glClearDepth");
5245 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5248 if (vp->X != 0 || vp->Y != 0 ||
5249 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5250 surface_load_ds_location(This->stencilBufferTarget, location);
5252 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5253 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5254 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5255 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5256 surface_load_ds_location(This->stencilBufferTarget, location);
5258 else if (Count > 0 && pRects && (
5259 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5260 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5261 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5262 surface_load_ds_location(This->stencilBufferTarget, location);
5266 if (Flags & WINED3DCLEAR_TARGET) {
5267 TRACE("Clearing screen with glClear to color %x\n", Color);
5268 glClearColor(D3DCOLOR_R(Color),
5272 checkGLcall("glClearColor");
5274 /* Clear ALL colors! */
5275 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5276 glMask = glMask | GL_COLOR_BUFFER_BIT;
5279 vp_rect.left = vp->X;
5280 vp_rect.top = vp->Y;
5281 vp_rect.right = vp->X + vp->Width;
5282 vp_rect.bottom = vp->Y + vp->Height;
5283 if (!(Count > 0 && pRects)) {
5284 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5285 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5287 if(This->render_offscreen) {
5288 glScissor(vp_rect.left, vp_rect.top,
5289 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5291 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5292 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5294 checkGLcall("glScissor");
5296 checkGLcall("glClear");
5298 /* Now process each rect in turn */
5299 for (i = 0; i < Count; i++) {
5300 /* Note gl uses lower left, width/height */
5301 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5302 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5303 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5305 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5306 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5307 curRect.x1, (target->currentDesc.Height - curRect.y2),
5308 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5310 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5311 * The rectangle is not cleared, no error is returned, but further rectanlges are
5312 * still cleared if they are valid
5314 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5315 TRACE("Rectangle with negative dimensions, ignoring\n");
5319 if(This->render_offscreen) {
5320 glScissor(curRect.x1, curRect.y1,
5321 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5323 glScissor(curRect.x1, drawable_height - curRect.y2,
5324 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5326 checkGLcall("glScissor");
5329 checkGLcall("glClear");
5333 /* Restore the old values (why..?) */
5334 if (Flags & WINED3DCLEAR_STENCIL) {
5335 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5337 if (Flags & WINED3DCLEAR_TARGET) {
5338 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5339 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5340 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5341 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5342 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5344 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5345 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5347 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5349 if (Flags & WINED3DCLEAR_ZBUFFER) {
5350 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5351 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5352 surface_modify_ds_location(This->stencilBufferTarget, location);
5357 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5358 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5361 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5367 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5368 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5370 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5372 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5373 Count, pRects, Flags, Color, Z, Stencil);
5375 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5376 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5377 /* TODO: What about depth stencil buffers without stencil bits? */
5378 return WINED3DERR_INVALIDCALL;
5381 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5388 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5389 WINED3DPRIMITIVETYPE primitive_type)
5391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5393 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5395 This->updateStateBlock->changed.primitive_type = TRUE;
5396 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5399 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5400 WINED3DPRIMITIVETYPE *primitive_type)
5402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5406 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5408 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5411 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5415 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5417 if(!This->stateBlock->vertexDecl) {
5418 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5419 return WINED3DERR_INVALIDCALL;
5422 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5423 if(This->stateBlock->streamIsUP) {
5424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5425 This->stateBlock->streamIsUP = FALSE;
5428 if(This->stateBlock->loadBaseVertexIndex != 0) {
5429 This->stateBlock->loadBaseVertexIndex = 0;
5430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5432 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5433 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5434 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5438 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5439 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5443 IWineD3DIndexBuffer *pIB;
5444 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5447 pIB = This->stateBlock->pIndexData;
5449 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5450 * without an index buffer set. (The first time at least...)
5451 * D3D8 simply dies, but I doubt it can do much harm to return
5452 * D3DERR_INVALIDCALL there as well. */
5453 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5454 return WINED3DERR_INVALIDCALL;
5457 if(!This->stateBlock->vertexDecl) {
5458 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5459 return WINED3DERR_INVALIDCALL;
5462 if(This->stateBlock->streamIsUP) {
5463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5464 This->stateBlock->streamIsUP = FALSE;
5466 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5468 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5469 This, minIndex, NumVertices, startIndex, index_count);
5471 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5472 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5478 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5479 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5483 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5484 vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5489 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5490 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5495 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5496 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5498 if(!This->stateBlock->vertexDecl) {
5499 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5500 return WINED3DERR_INVALIDCALL;
5503 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5504 vb = This->stateBlock->streamSource[0];
5505 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5506 if (vb) IWineD3DBuffer_Release(vb);
5507 This->stateBlock->streamOffset[0] = 0;
5508 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5509 This->stateBlock->streamIsUP = TRUE;
5510 This->stateBlock->loadBaseVertexIndex = 0;
5512 /* TODO: Only mark dirty if drawing from a different UP address */
5513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5515 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5516 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5518 /* MSDN specifies stream zero settings must be set to NULL */
5519 This->stateBlock->streamStride[0] = 0;
5520 This->stateBlock->streamSource[0] = NULL;
5522 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5523 * the new stream sources or use UP drawing again
5528 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5529 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5530 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5535 IWineD3DIndexBuffer *ib;
5537 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5538 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5539 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5541 if(!This->stateBlock->vertexDecl) {
5542 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5543 return WINED3DERR_INVALIDCALL;
5546 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5552 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5553 vb = This->stateBlock->streamSource[0];
5554 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5555 if (vb) IWineD3DBuffer_Release(vb);
5556 This->stateBlock->streamIsUP = TRUE;
5557 This->stateBlock->streamOffset[0] = 0;
5558 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5560 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5561 This->stateBlock->baseVertexIndex = 0;
5562 This->stateBlock->loadBaseVertexIndex = 0;
5563 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5567 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5568 idxStride, pIndexData, MinVertexIndex);
5570 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5571 This->stateBlock->streamSource[0] = NULL;
5572 This->stateBlock->streamStride[0] = 0;
5573 ib = This->stateBlock->pIndexData;
5575 IWineD3DIndexBuffer_Release(ib);
5576 This->stateBlock->pIndexData = NULL;
5578 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5579 * SetStreamSource to specify a vertex buffer
5585 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5586 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5590 /* Mark the state dirty until we have nicer tracking
5591 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5596 This->stateBlock->baseVertexIndex = 0;
5597 This->up_strided = DrawPrimStrideData;
5598 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5599 This->up_strided = NULL;
5603 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5604 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5605 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5608 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5610 /* Mark the state dirty until we have nicer tracking
5611 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5616 This->stateBlock->streamIsUP = TRUE;
5617 This->stateBlock->baseVertexIndex = 0;
5618 This->up_strided = DrawPrimStrideData;
5619 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5620 This->up_strided = NULL;
5624 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5625 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5626 * not callable by the app directly no parameter validation checks are needed here.
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5629 WINED3DLOCKED_BOX src;
5630 WINED3DLOCKED_BOX dst;
5632 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5634 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5635 * dirtification to improve loading performance.
5637 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5638 if(FAILED(hr)) return hr;
5639 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5641 IWineD3DVolume_UnlockBox(pSourceVolume);
5645 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5647 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5649 IWineD3DVolume_UnlockBox(pSourceVolume);
5651 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5656 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5657 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 HRESULT hr = WINED3D_OK;
5660 WINED3DRESOURCETYPE sourceType;
5661 WINED3DRESOURCETYPE destinationType;
5664 /* TODO: think about moving the code into IWineD3DBaseTexture */
5666 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5668 /* verify that the source and destination textures aren't NULL */
5669 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5670 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5671 This, pSourceTexture, pDestinationTexture);
5672 hr = WINED3DERR_INVALIDCALL;
5675 if (pSourceTexture == pDestinationTexture) {
5676 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5677 This, pSourceTexture, pDestinationTexture);
5678 hr = WINED3DERR_INVALIDCALL;
5680 /* Verify that the source and destination textures are the same type */
5681 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5682 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5684 if (sourceType != destinationType) {
5685 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5687 hr = WINED3DERR_INVALIDCALL;
5690 /* check that both textures have the identical numbers of levels */
5691 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5692 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5693 hr = WINED3DERR_INVALIDCALL;
5696 if (WINED3D_OK == hr) {
5697 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5699 /* Make sure that the destination texture is loaded */
5700 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5702 /* Update every surface level of the texture */
5703 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5705 switch (sourceType) {
5706 case WINED3DRTYPE_TEXTURE:
5708 IWineD3DSurface *srcSurface;
5709 IWineD3DSurface *destSurface;
5711 for (i = 0 ; i < levels ; ++i) {
5712 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5713 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5714 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5715 IWineD3DSurface_Release(srcSurface);
5716 IWineD3DSurface_Release(destSurface);
5717 if (WINED3D_OK != hr) {
5718 WARN("(%p) : Call to update surface failed\n", This);
5724 case WINED3DRTYPE_CUBETEXTURE:
5726 IWineD3DSurface *srcSurface;
5727 IWineD3DSurface *destSurface;
5728 WINED3DCUBEMAP_FACES faceType;
5730 for (i = 0 ; i < levels ; ++i) {
5731 /* Update each cube face */
5732 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5733 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5734 if (WINED3D_OK != hr) {
5735 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5737 TRACE("Got srcSurface %p\n", srcSurface);
5739 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5740 if (WINED3D_OK != hr) {
5741 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5743 TRACE("Got desrSurface %p\n", destSurface);
5745 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5746 IWineD3DSurface_Release(srcSurface);
5747 IWineD3DSurface_Release(destSurface);
5748 if (WINED3D_OK != hr) {
5749 WARN("(%p) : Call to update surface failed\n", This);
5757 case WINED3DRTYPE_VOLUMETEXTURE:
5759 IWineD3DVolume *srcVolume = NULL;
5760 IWineD3DVolume *destVolume = NULL;
5762 for (i = 0 ; i < levels ; ++i) {
5763 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5764 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5765 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5766 IWineD3DVolume_Release(srcVolume);
5767 IWineD3DVolume_Release(destVolume);
5768 if (WINED3D_OK != hr) {
5769 WARN("(%p) : Call to update volume failed\n", This);
5777 FIXME("(%p) : Unsupported source and destination type\n", This);
5778 hr = WINED3DERR_INVALIDCALL;
5785 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5786 IWineD3DSwapChain *swapChain;
5788 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5789 if(hr == WINED3D_OK) {
5790 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5791 IWineD3DSwapChain_Release(swapChain);
5796 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5798 IWineD3DBaseTextureImpl *texture;
5801 TRACE("(%p) : %p\n", This, pNumPasses);
5803 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5804 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5805 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5806 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5808 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5809 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5810 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5813 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5814 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5816 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5817 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5820 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5821 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5824 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5825 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5826 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5831 /* return a sensible default */
5834 TRACE("returning D3D_OK\n");
5838 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5842 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5843 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5844 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5845 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5847 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5852 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5856 PALETTEENTRY **palettes;
5858 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5860 if (PaletteNumber >= MAX_PALETTES) {
5861 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5862 return WINED3DERR_INVALIDCALL;
5865 if (PaletteNumber >= This->NumberOfPalettes) {
5866 NewSize = This->NumberOfPalettes;
5869 } while(PaletteNumber >= NewSize);
5870 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5872 ERR("Out of memory!\n");
5873 return E_OUTOFMEMORY;
5875 This->palettes = palettes;
5876 This->NumberOfPalettes = NewSize;
5879 if (!This->palettes[PaletteNumber]) {
5880 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5881 if (!This->palettes[PaletteNumber]) {
5882 ERR("Out of memory!\n");
5883 return E_OUTOFMEMORY;
5887 for (j = 0; j < 256; ++j) {
5888 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5889 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5890 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5891 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5893 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5894 TRACE("(%p) : returning\n", This);
5898 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5901 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5902 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5903 /* What happens in such situation isn't documented; Native seems to silently abort
5904 on such conditions. Return Invalid Call. */
5905 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5906 return WINED3DERR_INVALIDCALL;
5908 for (j = 0; j < 256; ++j) {
5909 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5910 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5911 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5912 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5914 TRACE("(%p) : returning\n", This);
5918 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5921 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5922 (tested with reference rasterizer). Return Invalid Call. */
5923 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5924 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5925 return WINED3DERR_INVALIDCALL;
5927 /*TODO: stateblocks */
5928 if (This->currentPalette != PaletteNumber) {
5929 This->currentPalette = PaletteNumber;
5930 dirtify_p8_texture_samplers(This);
5932 TRACE("(%p) : returning\n", This);
5936 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5938 if (PaletteNumber == NULL) {
5939 WARN("(%p) : returning Invalid Call\n", This);
5940 return WINED3DERR_INVALIDCALL;
5942 /*TODO: stateblocks */
5943 *PaletteNumber = This->currentPalette;
5944 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5948 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5953 FIXME("(%p) : stub\n", This);
5957 This->softwareVertexProcessing = bSoftware;
5962 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5967 FIXME("(%p) : stub\n", This);
5970 return This->softwareVertexProcessing;
5974 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5976 IWineD3DSwapChain *swapChain;
5979 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5981 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5982 if(hr == WINED3D_OK){
5983 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5984 IWineD3DSwapChain_Release(swapChain);
5986 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5992 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5995 if(nSegments != 0.0f) {
5998 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6005 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6010 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6016 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6018 /** TODO: remove casts to IWineD3DSurfaceImpl
6019 * NOTE: move code to surface to accomplish this
6020 ****************************************/
6021 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6022 int srcWidth, srcHeight;
6023 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6024 WINED3DFORMAT destFormat, srcFormat;
6026 int srcLeft, destLeft, destTop;
6027 WINED3DPOOL srcPool, destPool;
6029 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6030 glDescriptor *glDescription = NULL;
6031 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6035 CONVERT_TYPES convert = NO_CONVERSION;
6037 WINED3DSURFACE_DESC winedesc;
6039 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6040 memset(&winedesc, 0, sizeof(winedesc));
6041 winedesc.Width = &srcSurfaceWidth;
6042 winedesc.Height = &srcSurfaceHeight;
6043 winedesc.Pool = &srcPool;
6044 winedesc.Format = &srcFormat;
6046 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6048 winedesc.Width = &destSurfaceWidth;
6049 winedesc.Height = &destSurfaceHeight;
6050 winedesc.Pool = &destPool;
6051 winedesc.Format = &destFormat;
6052 winedesc.Size = &destSize;
6054 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6056 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6057 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6058 return WINED3DERR_INVALIDCALL;
6061 /* This call loads the opengl surface directly, instead of copying the surface to the
6062 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6063 * copy in sysmem and use regular surface loading.
6065 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6066 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6067 if(convert != NO_CONVERSION) {
6068 return IWineD3DSurface_BltFast(pDestinationSurface,
6069 pDestPoint ? pDestPoint->x : 0,
6070 pDestPoint ? pDestPoint->y : 0,
6071 pSourceSurface, pSourceRect, 0);
6074 if (destFormat == WINED3DFMT_UNKNOWN) {
6075 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6076 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6078 /* Get the update surface description */
6079 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6082 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6085 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6086 checkGLcall("glActiveTextureARB");
6089 /* Make sure the surface is loaded and up to date */
6090 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6091 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6093 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6095 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6096 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6098 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6099 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6100 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6101 srcLeft = pSourceRect ? pSourceRect->left : 0;
6102 destLeft = pDestPoint ? pDestPoint->x : 0;
6103 destTop = pDestPoint ? pDestPoint->y : 0;
6106 /* This function doesn't support compressed textures
6107 the pitch is just bytesPerPixel * width */
6108 if(srcWidth != srcSurfaceWidth || srcLeft ){
6109 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6110 offset += srcLeft * src_format_desc->byte_count;
6111 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6113 /* TODO DXT formats */
6115 if(pSourceRect != NULL && pSourceRect->top != 0){
6116 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6118 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6119 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6120 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6123 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6125 /* need to lock the surface to get the data */
6126 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6131 /* TODO: Cube and volume support */
6133 /* not a whole row so we have to do it a line at a time */
6136 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6137 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6139 for (j = destTop; j < (srcHeight + destTop); ++j)
6141 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6142 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6146 } else { /* Full width, so just write out the whole texture */
6147 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6149 if (WINED3DFMT_DXT1 == destFormat ||
6150 WINED3DFMT_DXT2 == destFormat ||
6151 WINED3DFMT_DXT3 == destFormat ||
6152 WINED3DFMT_DXT4 == destFormat ||
6153 WINED3DFMT_DXT5 == destFormat) {
6154 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6155 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6156 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6157 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6158 } if (destFormat != srcFormat) {
6159 FIXME("Updating mixed format compressed texture is not curretly support\n");
6161 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6162 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6165 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6170 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6171 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6174 checkGLcall("glTexSubImage2D");
6178 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6179 sampler = This->rev_tex_unit_map[0];
6180 if (sampler != -1) {
6181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6187 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6189 struct WineD3DRectPatch *patch;
6190 GLenum old_primitive_type;
6194 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6196 if(!(Handle || pRectPatchInfo)) {
6197 /* TODO: Write a test for the return value, thus the FIXME */
6198 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6199 return WINED3DERR_INVALIDCALL;
6203 i = PATCHMAP_HASHFUNC(Handle);
6205 LIST_FOR_EACH(e, &This->patches[i]) {
6206 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6207 if(patch->Handle == Handle) {
6214 TRACE("Patch does not exist. Creating a new one\n");
6215 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6216 patch->Handle = Handle;
6217 list_add_head(&This->patches[i], &patch->entry);
6219 TRACE("Found existing patch %p\n", patch);
6222 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6223 * attributes we have to tesselate, read back, and draw. This needs a patch
6224 * management structure instance. Create one.
6226 * A possible improvement is to check if a vertex shader is used, and if not directly
6229 FIXME("Drawing an uncached patch. This is slow\n");
6230 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6233 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6234 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6235 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6237 TRACE("Tesselation density or patch info changed, retesselating\n");
6239 if(pRectPatchInfo) {
6240 patch->RectPatchInfo = *pRectPatchInfo;
6242 patch->numSegs[0] = pNumSegs[0];
6243 patch->numSegs[1] = pNumSegs[1];
6244 patch->numSegs[2] = pNumSegs[2];
6245 patch->numSegs[3] = pNumSegs[3];
6247 hr = tesselate_rectpatch(This, patch);
6249 WARN("Patch tesselation failed\n");
6251 /* Do not release the handle to store the params of the patch */
6253 HeapFree(GetProcessHeap(), 0, patch);
6259 This->currentPatch = patch;
6260 old_primitive_type = This->stateBlock->gl_primitive_type;
6261 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6262 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6263 This->stateBlock->gl_primitive_type = old_primitive_type;
6264 This->currentPatch = NULL;
6266 /* Destroy uncached patches */
6268 HeapFree(GetProcessHeap(), 0, patch->mem);
6269 HeapFree(GetProcessHeap(), 0, patch);
6274 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6276 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6277 FIXME("(%p) : Stub\n", This);
6281 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6284 struct WineD3DRectPatch *patch;
6286 TRACE("(%p) Handle(%d)\n", This, Handle);
6288 i = PATCHMAP_HASHFUNC(Handle);
6289 LIST_FOR_EACH(e, &This->patches[i]) {
6290 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6291 if(patch->Handle == Handle) {
6292 TRACE("Deleting patch %p\n", patch);
6293 list_remove(&patch->entry);
6294 HeapFree(GetProcessHeap(), 0, patch->mem);
6295 HeapFree(GetProcessHeap(), 0, patch);
6300 /* TODO: Write a test for the return value */
6301 FIXME("Attempt to destroy nonexistent patch\n");
6302 return WINED3DERR_INVALIDCALL;
6305 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6307 IWineD3DSwapChain *swapchain;
6309 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6310 if (SUCCEEDED(hr)) {
6311 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6318 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6319 const WINED3DRECT *rect, const float color[4])
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6322 IWineD3DSwapChain *swapchain;
6324 swapchain = get_swapchain(surface);
6328 TRACE("Surface %p is onscreen\n", surface);
6330 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6332 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6333 buffer = surface_get_gl_buffer(surface, swapchain);
6334 glDrawBuffer(buffer);
6335 checkGLcall("glDrawBuffer()");
6337 TRACE("Surface %p is offscreen\n", surface);
6339 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6341 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6342 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6343 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6344 checkGLcall("glFramebufferRenderbufferEXT");
6348 glEnable(GL_SCISSOR_TEST);
6350 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6352 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6353 rect->x2 - rect->x1, rect->y2 - rect->y1);
6355 checkGLcall("glScissor");
6356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6358 glDisable(GL_SCISSOR_TEST);
6360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6362 glDisable(GL_BLEND);
6363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6365 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6368 glClearColor(color[0], color[1], color[2], color[3]);
6369 glClear(GL_COLOR_BUFFER_BIT);
6370 checkGLcall("glClear");
6372 if (This->activeContext->current_fbo) {
6373 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6375 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6376 checkGLcall("glBindFramebuffer()");
6379 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6380 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6381 glDrawBuffer(GL_BACK);
6382 checkGLcall("glDrawBuffer()");
6388 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6389 unsigned int r, g, b, a;
6392 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6393 destfmt == WINED3DFMT_R8G8B8)
6396 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6398 a = (color & 0xff000000) >> 24;
6399 r = (color & 0x00ff0000) >> 16;
6400 g = (color & 0x0000ff00) >> 8;
6401 b = (color & 0x000000ff) >> 0;
6405 case WINED3DFMT_R5G6B5:
6406 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6413 TRACE("Returning %08x\n", ret);
6416 case WINED3DFMT_X1R5G5B5:
6417 case WINED3DFMT_A1R5G5B5:
6426 TRACE("Returning %08x\n", ret);
6429 case WINED3DFMT_A8_UNORM:
6430 TRACE("Returning %08x\n", a);
6433 case WINED3DFMT_X4R4G4B4:
6434 case WINED3DFMT_A4R4G4B4:
6443 TRACE("Returning %08x\n", ret);
6446 case WINED3DFMT_R3G3B2:
6453 TRACE("Returning %08x\n", ret);
6456 case WINED3DFMT_X8B8G8R8:
6457 case WINED3DFMT_R8G8B8A8_UNORM:
6462 TRACE("Returning %08x\n", ret);
6465 case WINED3DFMT_A2R10G10B10:
6467 r = (r * 1024) / 256;
6468 g = (g * 1024) / 256;
6469 b = (b * 1024) / 256;
6474 TRACE("Returning %08x\n", ret);
6477 case WINED3DFMT_R10G10B10A2_UNORM:
6479 r = (r * 1024) / 256;
6480 g = (g * 1024) / 256;
6481 b = (b * 1024) / 256;
6486 TRACE("Returning %08x\n", ret);
6490 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6495 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6497 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6499 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6501 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6502 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6503 return WINED3DERR_INVALIDCALL;
6506 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6507 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6508 color_fill_fbo(iface, pSurface, pRect, c);
6511 /* Just forward this to the DirectDraw blitting engine */
6512 memset(&BltFx, 0, sizeof(BltFx));
6513 BltFx.dwSize = sizeof(BltFx);
6514 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6515 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6516 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6520 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6521 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6523 IWineD3DResource *resource;
6524 IWineD3DSurface *surface;
6527 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6530 ERR("Failed to get resource, hr %#x\n", hr);
6534 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6536 FIXME("Only supported on surface resources\n");
6537 IWineD3DResource_Release(resource);
6541 surface = (IWineD3DSurface *)resource;
6543 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6545 color_fill_fbo(iface, surface, NULL, color);
6552 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6554 c = ((DWORD)(color[2] * 255.0));
6555 c |= ((DWORD)(color[1] * 255.0)) << 8;
6556 c |= ((DWORD)(color[0] * 255.0)) << 16;
6557 c |= ((DWORD)(color[3] * 255.0)) << 24;
6559 /* Just forward this to the DirectDraw blitting engine */
6560 memset(&BltFx, 0, sizeof(BltFx));
6561 BltFx.dwSize = sizeof(BltFx);
6562 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6563 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6566 ERR("Blt failed, hr %#x\n", hr);
6570 IWineD3DResource_Release(resource);
6573 /* rendertarget and depth stencil functions */
6574 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6577 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6578 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6579 return WINED3DERR_INVALIDCALL;
6582 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6583 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6584 /* Note inc ref on returned surface */
6585 if(*ppRenderTarget != NULL)
6586 IWineD3DSurface_AddRef(*ppRenderTarget);
6590 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6592 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6593 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6594 IWineD3DSwapChainImpl *Swapchain;
6597 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6599 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6600 if(hr != WINED3D_OK) {
6601 ERR("Can't get the swapchain\n");
6605 /* Make sure to release the swapchain */
6606 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6608 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6609 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6610 return WINED3DERR_INVALIDCALL;
6612 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6613 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6614 return WINED3DERR_INVALIDCALL;
6617 if(Swapchain->frontBuffer != Front) {
6618 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6620 if(Swapchain->frontBuffer)
6621 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6622 Swapchain->frontBuffer = Front;
6624 if(Swapchain->frontBuffer) {
6625 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6629 if(Back && !Swapchain->backBuffer) {
6630 /* We need memory for the back buffer array - only one back buffer this way */
6631 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6632 if(!Swapchain->backBuffer) {
6633 ERR("Out of memory\n");
6634 return E_OUTOFMEMORY;
6638 if(Swapchain->backBuffer[0] != Back) {
6639 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6641 /* What to do about the context here in the case of multithreading? Not sure.
6642 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6645 if(!Swapchain->backBuffer[0]) {
6646 /* GL was told to draw to the front buffer at creation,
6649 glDrawBuffer(GL_BACK);
6650 checkGLcall("glDrawBuffer(GL_BACK)");
6651 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6652 Swapchain->presentParms.BackBufferCount = 1;
6654 /* That makes problems - disable for now */
6655 /* glDrawBuffer(GL_FRONT); */
6656 checkGLcall("glDrawBuffer(GL_FRONT)");
6657 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6658 Swapchain->presentParms.BackBufferCount = 0;
6662 if(Swapchain->backBuffer[0])
6663 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6664 Swapchain->backBuffer[0] = Back;
6666 if(Swapchain->backBuffer[0]) {
6667 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6669 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6670 Swapchain->backBuffer = NULL;
6678 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6680 *ppZStencilSurface = This->stencilBufferTarget;
6681 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6683 if(*ppZStencilSurface != NULL) {
6684 /* Note inc ref on returned surface */
6685 IWineD3DSurface_AddRef(*ppZStencilSurface);
6688 return WINED3DERR_NOTFOUND;
6692 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6693 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6696 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6697 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6699 POINT offset = {0, 0};
6701 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6702 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6703 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6704 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6707 case WINED3DTEXF_LINEAR:
6708 gl_filter = GL_LINEAR;
6712 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6713 case WINED3DTEXF_NONE:
6714 case WINED3DTEXF_POINT:
6715 gl_filter = GL_NEAREST;
6719 /* Attach src surface to src fbo */
6720 src_swapchain = get_swapchain(src_surface);
6721 if (src_swapchain) {
6722 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6724 TRACE("Source surface %p is onscreen\n", src_surface);
6725 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6726 /* Make sure the drawable is up to date. In the offscreen case
6727 * attach_surface_fbo() implicitly takes care of this. */
6728 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6730 if(buffer == GL_FRONT) {
6733 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6734 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6735 h = windowsize.bottom - windowsize.top;
6736 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6737 src_rect->y1 = offset.y + h - src_rect->y1;
6738 src_rect->y2 = offset.y + h - src_rect->y2;
6740 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6741 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6745 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6746 glReadBuffer(buffer);
6747 checkGLcall("glReadBuffer()");
6749 TRACE("Source surface %p is offscreen\n", src_surface);
6751 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6752 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6753 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6754 checkGLcall("glReadBuffer()");
6755 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6756 checkGLcall("glFramebufferRenderbufferEXT");
6760 /* Attach dst surface to dst fbo */
6761 dst_swapchain = get_swapchain(dst_surface);
6762 if (dst_swapchain) {
6763 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6765 TRACE("Destination surface %p is onscreen\n", dst_surface);
6766 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6767 /* Make sure the drawable is up to date. In the offscreen case
6768 * attach_surface_fbo() implicitly takes care of this. */
6769 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6771 if(buffer == GL_FRONT) {
6774 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6775 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6776 h = windowsize.bottom - windowsize.top;
6777 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6778 dst_rect->y1 = offset.y + h - dst_rect->y1;
6779 dst_rect->y2 = offset.y + h - dst_rect->y2;
6781 /* Screen coords = window coords, surface height = window height */
6782 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6783 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6787 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6788 glDrawBuffer(buffer);
6789 checkGLcall("glDrawBuffer()");
6791 TRACE("Destination surface %p is offscreen\n", dst_surface);
6793 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6794 if(!src_swapchain) {
6795 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6799 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6800 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6801 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6802 checkGLcall("glDrawBuffer()");
6803 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6804 checkGLcall("glFramebufferRenderbufferEXT");
6806 glDisable(GL_SCISSOR_TEST);
6807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6810 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6811 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6812 checkGLcall("glBlitFramebuffer()");
6814 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6815 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6816 checkGLcall("glBlitFramebuffer()");
6819 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6821 if (This->activeContext->current_fbo) {
6822 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6824 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6825 checkGLcall("glBindFramebuffer()");
6828 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6829 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6830 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6831 glDrawBuffer(GL_BACK);
6832 checkGLcall("glDrawBuffer()");
6837 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6839 WINED3DVIEWPORT viewport;
6841 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6843 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6844 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6845 This, RenderTargetIndex, GL_LIMITS(buffers));
6846 return WINED3DERR_INVALIDCALL;
6849 /* MSDN says that null disables the render target
6850 but a device must always be associated with a render target
6851 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6853 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6854 FIXME("Trying to set render target 0 to NULL\n");
6855 return WINED3DERR_INVALIDCALL;
6857 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6858 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);
6859 return WINED3DERR_INVALIDCALL;
6862 /* If we are trying to set what we already have, don't bother */
6863 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6864 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6867 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6868 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6869 This->render_targets[RenderTargetIndex] = pRenderTarget;
6871 /* Render target 0 is special */
6872 if(RenderTargetIndex == 0) {
6873 /* Finally, reset the viewport as the MSDN states. */
6874 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6875 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6878 viewport.MaxZ = 1.0f;
6879 viewport.MinZ = 0.0f;
6880 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6881 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6882 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6889 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6891 HRESULT hr = WINED3D_OK;
6892 IWineD3DSurface *tmp;
6894 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6896 if (pNewZStencil == This->stencilBufferTarget) {
6897 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6899 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6900 * depending on the renter target implementation being used.
6901 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6902 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6903 * stencil buffer and incur an extra memory overhead
6904 ******************************************************/
6906 if (This->stencilBufferTarget) {
6907 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6908 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6909 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6911 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6912 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6913 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6917 tmp = This->stencilBufferTarget;
6918 This->stencilBufferTarget = pNewZStencil;
6919 /* should we be calling the parent or the wined3d surface? */
6920 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6921 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6924 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6925 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6935 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6936 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6938 /* TODO: the use of Impl is deprecated. */
6939 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6940 WINED3DLOCKED_RECT lockedRect;
6942 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6944 /* some basic validation checks */
6945 if(This->cursorTexture) {
6946 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6948 glDeleteTextures(1, &This->cursorTexture);
6950 This->cursorTexture = 0;
6953 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6954 This->haveHardwareCursor = TRUE;
6956 This->haveHardwareCursor = FALSE;
6959 WINED3DLOCKED_RECT rect;
6961 /* MSDN: Cursor must be A8R8G8B8 */
6962 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6964 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6965 return WINED3DERR_INVALIDCALL;
6968 /* MSDN: Cursor must be smaller than the display mode */
6969 if(pSur->currentDesc.Width > This->ddraw_width ||
6970 pSur->currentDesc.Height > This->ddraw_height) {
6971 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);
6972 return WINED3DERR_INVALIDCALL;
6975 if (!This->haveHardwareCursor) {
6976 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6978 /* Do not store the surface's pointer because the application may
6979 * release it after setting the cursor image. Windows doesn't
6980 * addref the set surface, so we can't do this either without
6981 * creating circular refcount dependencies. Copy out the gl texture
6984 This->cursorWidth = pSur->currentDesc.Width;
6985 This->cursorHeight = pSur->currentDesc.Height;
6986 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6988 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6989 char *mem, *bits = rect.pBits;
6990 GLint intfmt = glDesc->glInternal;
6991 GLint format = glDesc->glFormat;
6992 GLint type = glDesc->glType;
6993 INT height = This->cursorHeight;
6994 INT width = This->cursorWidth;
6995 INT bpp = glDesc->byte_count;
6998 /* Reformat the texture memory (pitch and width can be
7000 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7001 for(i = 0; i < height; i++)
7002 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7003 IWineD3DSurface_UnlockRect(pCursorBitmap);
7006 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7007 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7008 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7011 /* Make sure that a proper texture unit is selected */
7012 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7013 checkGLcall("glActiveTextureARB");
7014 sampler = This->rev_tex_unit_map[0];
7015 if (sampler != -1) {
7016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7018 /* Create a new cursor texture */
7019 glGenTextures(1, &This->cursorTexture);
7020 checkGLcall("glGenTextures");
7021 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7022 checkGLcall("glBindTexture");
7023 /* Copy the bitmap memory into the cursor texture */
7024 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7025 HeapFree(GetProcessHeap(), 0, mem);
7026 checkGLcall("glTexImage2D");
7028 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7029 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7030 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7037 FIXME("A cursor texture was not returned.\n");
7038 This->cursorTexture = 0;
7043 /* Draw a hardware cursor */
7044 ICONINFO cursorInfo;
7046 /* Create and clear maskBits because it is not needed for
7047 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7049 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7050 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7051 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7052 WINED3DLOCK_NO_DIRTY_UPDATE |
7053 WINED3DLOCK_READONLY
7055 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7056 pSur->currentDesc.Height);
7058 cursorInfo.fIcon = FALSE;
7059 cursorInfo.xHotspot = XHotSpot;
7060 cursorInfo.yHotspot = YHotSpot;
7061 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7062 pSur->currentDesc.Height, 1,
7064 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7065 pSur->currentDesc.Height, 1,
7066 32, lockedRect.pBits);
7067 IWineD3DSurface_UnlockRect(pCursorBitmap);
7068 /* Create our cursor and clean up. */
7069 cursor = CreateIconIndirect(&cursorInfo);
7071 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7072 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7073 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7074 This->hardwareCursor = cursor;
7075 HeapFree(GetProcessHeap(), 0, maskBits);
7079 This->xHotSpot = XHotSpot;
7080 This->yHotSpot = YHotSpot;
7084 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7086 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7088 This->xScreenSpace = XScreenSpace;
7089 This->yScreenSpace = YScreenSpace;
7095 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7097 BOOL oldVisible = This->bCursorVisible;
7100 TRACE("(%p) : visible(%d)\n", This, bShow);
7103 * When ShowCursor is first called it should make the cursor appear at the OS's last
7104 * known cursor position. Because of this, some applications just repetitively call
7105 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7108 This->xScreenSpace = pt.x;
7109 This->yScreenSpace = pt.y;
7111 if (This->haveHardwareCursor) {
7112 This->bCursorVisible = bShow;
7114 SetCursor(This->hardwareCursor);
7120 if (This->cursorTexture)
7121 This->bCursorVisible = bShow;
7127 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7129 IWineD3DResourceImpl *resource;
7130 TRACE("(%p) : state (%u)\n", This, This->state);
7132 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7133 switch (This->state) {
7136 case WINED3DERR_DEVICELOST:
7138 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7139 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7140 return WINED3DERR_DEVICENOTRESET;
7142 return WINED3DERR_DEVICELOST;
7144 case WINED3DERR_DRIVERINTERNALERROR:
7145 return WINED3DERR_DRIVERINTERNALERROR;
7149 return WINED3DERR_DRIVERINTERNALERROR;
7153 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7155 /** FIXME: Resource tracking needs to be done,
7156 * The closes we can do to this is set the priorities of all managed textures low
7157 * and then reset them.
7158 ***********************************************************/
7159 FIXME("(%p) : stub\n", This);
7163 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7165 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7167 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7168 if(surface->Flags & SFLAG_DIBSECTION) {
7169 /* Release the DC */
7170 SelectObject(surface->hDC, surface->dib.holdbitmap);
7171 DeleteDC(surface->hDC);
7172 /* Release the DIB section */
7173 DeleteObject(surface->dib.DIBsection);
7174 surface->dib.bitmap_data = NULL;
7175 surface->resource.allocatedMemory = NULL;
7176 surface->Flags &= ~SFLAG_DIBSECTION;
7178 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7179 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7180 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7181 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7182 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7183 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7185 surface->pow2Width = surface->pow2Height = 1;
7186 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7187 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7189 surface->glRect.left = 0;
7190 surface->glRect.top = 0;
7191 surface->glRect.right = surface->pow2Width;
7192 surface->glRect.bottom = surface->pow2Height;
7194 if(surface->glDescription.textureName) {
7195 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7197 glDeleteTextures(1, &surface->glDescription.textureName);
7199 surface->glDescription.textureName = 0;
7200 surface->Flags &= ~SFLAG_CLIENT;
7202 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7203 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7204 surface->Flags |= SFLAG_NONPOW2;
7206 surface->Flags &= ~SFLAG_NONPOW2;
7208 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7209 surface->resource.allocatedMemory = NULL;
7210 surface->resource.heapMemory = NULL;
7211 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7212 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7213 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7214 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7216 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7220 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7221 TRACE("Unloading resource %p\n", resource);
7222 IWineD3DResource_UnLoad(resource);
7223 IWineD3DResource_Release(resource);
7227 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7230 WINED3DDISPLAYMODE m;
7233 /* All Windowed modes are supported, as is leaving the current mode */
7234 if(pp->Windowed) return TRUE;
7235 if(!pp->BackBufferWidth) return TRUE;
7236 if(!pp->BackBufferHeight) return TRUE;
7238 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7239 for(i = 0; i < count; i++) {
7240 memset(&m, 0, sizeof(m));
7241 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7243 ERR("EnumAdapterModes failed\n");
7245 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7246 /* Mode found, it is supported */
7250 /* Mode not found -> not supported */
7254 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7256 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7258 IWineD3DBaseShaderImpl *shader;
7260 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7261 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7262 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7266 if(This->depth_blt_texture) {
7267 glDeleteTextures(1, &This->depth_blt_texture);
7268 This->depth_blt_texture = 0;
7270 if (This->depth_blt_rb) {
7271 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7272 This->depth_blt_rb = 0;
7273 This->depth_blt_rb_w = 0;
7274 This->depth_blt_rb_h = 0;
7278 This->blitter->free_private(iface);
7279 This->frag_pipe->free_private(iface);
7280 This->shader_backend->shader_free_private(iface);
7283 for (i = 0; i < GL_LIMITS(textures); i++) {
7284 /* Textures are recreated below */
7285 glDeleteTextures(1, &This->dummyTextureName[i]);
7286 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7287 This->dummyTextureName[i] = 0;
7291 while(This->numContexts) {
7292 DestroyContext(This, This->contexts[0]);
7294 This->activeContext = NULL;
7295 HeapFree(GetProcessHeap(), 0, swapchain->context);
7296 swapchain->context = NULL;
7297 swapchain->num_contexts = 0;
7300 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7302 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7304 IWineD3DSurfaceImpl *target;
7306 /* Recreate the primary swapchain's context */
7307 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7308 if(swapchain->backBuffer) {
7309 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7311 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7313 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7314 &swapchain->presentParms);
7315 swapchain->num_contexts = 1;
7316 This->activeContext = swapchain->context[0];
7318 create_dummy_textures(This);
7320 hr = This->shader_backend->shader_alloc_private(iface);
7322 ERR("Failed to recreate shader private data\n");
7325 hr = This->frag_pipe->alloc_private(iface);
7327 TRACE("Fragment pipeline private data couldn't be allocated\n");
7330 hr = This->blitter->alloc_private(iface);
7332 TRACE("Blitter private data couldn't be allocated\n");
7339 This->blitter->free_private(iface);
7340 This->frag_pipe->free_private(iface);
7341 This->shader_backend->shader_free_private(iface);
7345 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7347 IWineD3DSwapChainImpl *swapchain;
7349 BOOL DisplayModeChanged = FALSE;
7350 WINED3DDISPLAYMODE mode;
7351 TRACE("(%p)\n", This);
7353 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7355 ERR("Failed to get the first implicit swapchain\n");
7359 if(!is_display_mode_supported(This, pPresentationParameters)) {
7360 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7361 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7362 pPresentationParameters->BackBufferHeight);
7363 return WINED3DERR_INVALIDCALL;
7366 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7367 * on an existing gl context, so there's no real need for recreation.
7369 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7371 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7373 TRACE("New params:\n");
7374 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7375 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7376 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7377 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7378 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7379 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7380 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7381 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7382 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7383 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7384 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7385 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7386 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7388 /* No special treatment of these parameters. Just store them */
7389 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7390 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7391 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7392 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7394 /* What to do about these? */
7395 if(pPresentationParameters->BackBufferCount != 0 &&
7396 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7397 ERR("Cannot change the back buffer count yet\n");
7399 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7400 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7401 ERR("Cannot change the back buffer format yet\n");
7403 if(pPresentationParameters->hDeviceWindow != NULL &&
7404 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7405 ERR("Cannot change the device window yet\n");
7407 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7408 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7409 return WINED3DERR_INVALIDCALL;
7412 /* Reset the depth stencil */
7413 if (pPresentationParameters->EnableAutoDepthStencil)
7414 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7416 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7418 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7420 if(pPresentationParameters->Windowed) {
7421 mode.Width = swapchain->orig_width;
7422 mode.Height = swapchain->orig_height;
7423 mode.RefreshRate = 0;
7424 mode.Format = swapchain->presentParms.BackBufferFormat;
7426 mode.Width = pPresentationParameters->BackBufferWidth;
7427 mode.Height = pPresentationParameters->BackBufferHeight;
7428 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7429 mode.Format = swapchain->presentParms.BackBufferFormat;
7432 /* Should Width == 800 && Height == 0 set 800x600? */
7433 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7434 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7435 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7439 if(!pPresentationParameters->Windowed) {
7440 DisplayModeChanged = TRUE;
7442 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7443 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7445 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7446 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7447 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7449 if(This->auto_depth_stencil_buffer) {
7450 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7454 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7455 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7456 DisplayModeChanged) {
7458 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7460 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7461 if(swapchain->presentParms.Windowed) {
7462 /* switch from windowed to fs */
7463 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7464 pPresentationParameters->BackBufferWidth,
7465 pPresentationParameters->BackBufferHeight);
7467 /* Fullscreen -> fullscreen mode change */
7468 MoveWindow(swapchain->win_handle, 0, 0,
7469 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7472 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7473 /* Fullscreen -> windowed switch */
7474 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7476 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7477 } else if(!pPresentationParameters->Windowed) {
7478 DWORD style = This->style, exStyle = This->exStyle;
7479 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7480 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7481 * Reset to clear up their mess. Guild Wars also loses the device during that.
7485 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7486 pPresentationParameters->BackBufferWidth,
7487 pPresentationParameters->BackBufferHeight);
7488 This->style = style;
7489 This->exStyle = exStyle;
7492 TRACE("Resetting stateblock\n");
7493 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7494 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7496 /* Note: No parent needed for initial internal stateblock */
7497 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7498 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7499 else TRACE("Created stateblock %p\n", This->stateBlock);
7500 This->updateStateBlock = This->stateBlock;
7501 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7503 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7505 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7508 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7509 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7511 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7517 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7519 /** FIXME: always true at the moment **/
7520 if(!bEnableDialogs) {
7521 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7527 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7529 TRACE("(%p) : pParameters %p\n", This, pParameters);
7531 *pParameters = This->createParms;
7535 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7536 IWineD3DSwapChain *swapchain;
7538 TRACE("Relaying to swapchain\n");
7540 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7541 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7542 IWineD3DSwapChain_Release(swapchain);
7547 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7548 IWineD3DSwapChain *swapchain;
7550 TRACE("Relaying to swapchain\n");
7552 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7553 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7554 IWineD3DSwapChain_Release(swapchain);
7560 /** ********************************************************
7561 * Notification functions
7562 ** ********************************************************/
7563 /** This function must be called in the release of a resource when ref == 0,
7564 * the contents of resource must still be correct,
7565 * any handles to other resource held by the caller must be closed
7566 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7567 *****************************************************/
7568 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7571 TRACE("(%p) : Adding Resource %p\n", This, resource);
7572 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7575 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7578 TRACE("(%p) : Removing resource %p\n", This, resource);
7580 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7584 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7586 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7589 TRACE("(%p) : resource %p\n", This, resource);
7591 context_resource_released(iface, resource, type);
7594 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7595 case WINED3DRTYPE_SURFACE: {
7598 /* Cleanup any FBO attachments if d3d is enabled */
7599 if(This->d3d_initialized) {
7600 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7601 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7603 TRACE("Last active render target destroyed\n");
7604 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7605 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7606 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7607 * and the lastActiveRenderTarget member shouldn't matter
7610 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7611 TRACE("Activating primary back buffer\n");
7612 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7613 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7614 /* Single buffering environment */
7615 TRACE("Activating primary front buffer\n");
7616 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7618 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7619 /* Implicit render target destroyed, that means the device is being destroyed
7620 * whatever we set here, it shouldn't matter
7622 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7625 /* May happen during ddraw uninitialization */
7626 TRACE("Render target set, but swapchain does not exist!\n");
7627 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7631 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7632 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7633 This->render_targets[i] = NULL;
7636 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7637 This->stencilBufferTarget = NULL;
7643 case WINED3DRTYPE_TEXTURE:
7644 case WINED3DRTYPE_CUBETEXTURE:
7645 case WINED3DRTYPE_VOLUMETEXTURE:
7646 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7647 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7648 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7649 This->stateBlock->textures[counter] = NULL;
7651 if (This->updateStateBlock != This->stateBlock ){
7652 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7653 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7654 This->updateStateBlock->textures[counter] = NULL;
7659 case WINED3DRTYPE_VOLUME:
7660 /* TODO: nothing really? */
7662 case WINED3DRTYPE_VERTEXBUFFER:
7665 TRACE("Cleaning up stream pointers\n");
7667 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7668 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7669 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7671 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7672 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7673 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7674 This->updateStateBlock->streamSource[streamNumber] = 0;
7675 /* Set changed flag? */
7678 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) */
7679 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7680 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7681 This->stateBlock->streamSource[streamNumber] = 0;
7687 case WINED3DRTYPE_INDEXBUFFER:
7688 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7689 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7690 This->updateStateBlock->pIndexData = NULL;
7693 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7694 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7695 This->stateBlock->pIndexData = NULL;
7700 case WINED3DRTYPE_BUFFER:
7701 /* Nothing to do, yet.*/
7705 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7710 /* Remove the resource from the resourceStore */
7711 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7713 TRACE("Resource released\n");
7717 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7719 IWineD3DResourceImpl *resource, *cursor;
7721 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7723 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7724 TRACE("enumerating resource %p\n", resource);
7725 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7726 ret = pCallback((IWineD3DResource *) resource, pData);
7727 if(ret == S_FALSE) {
7728 TRACE("Canceling enumeration\n");
7735 /**********************************************************
7736 * IWineD3DDevice VTbl follows
7737 **********************************************************/
7739 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7741 /*** IUnknown methods ***/
7742 IWineD3DDeviceImpl_QueryInterface,
7743 IWineD3DDeviceImpl_AddRef,
7744 IWineD3DDeviceImpl_Release,
7745 /*** IWineD3DDevice methods ***/
7746 IWineD3DDeviceImpl_GetParent,
7747 /*** Creation methods**/
7748 IWineD3DDeviceImpl_CreateBuffer,
7749 IWineD3DDeviceImpl_CreateVertexBuffer,
7750 IWineD3DDeviceImpl_CreateIndexBuffer,
7751 IWineD3DDeviceImpl_CreateStateBlock,
7752 IWineD3DDeviceImpl_CreateSurface,
7753 IWineD3DDeviceImpl_CreateRendertargetView,
7754 IWineD3DDeviceImpl_CreateTexture,
7755 IWineD3DDeviceImpl_CreateVolumeTexture,
7756 IWineD3DDeviceImpl_CreateVolume,
7757 IWineD3DDeviceImpl_CreateCubeTexture,
7758 IWineD3DDeviceImpl_CreateQuery,
7759 IWineD3DDeviceImpl_CreateSwapChain,
7760 IWineD3DDeviceImpl_CreateVertexDeclaration,
7761 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7762 IWineD3DDeviceImpl_CreateVertexShader,
7763 IWineD3DDeviceImpl_CreatePixelShader,
7764 IWineD3DDeviceImpl_CreatePalette,
7765 /*** Odd functions **/
7766 IWineD3DDeviceImpl_Init3D,
7767 IWineD3DDeviceImpl_InitGDI,
7768 IWineD3DDeviceImpl_Uninit3D,
7769 IWineD3DDeviceImpl_UninitGDI,
7770 IWineD3DDeviceImpl_SetMultithreaded,
7771 IWineD3DDeviceImpl_EvictManagedResources,
7772 IWineD3DDeviceImpl_GetAvailableTextureMem,
7773 IWineD3DDeviceImpl_GetBackBuffer,
7774 IWineD3DDeviceImpl_GetCreationParameters,
7775 IWineD3DDeviceImpl_GetDeviceCaps,
7776 IWineD3DDeviceImpl_GetDirect3D,
7777 IWineD3DDeviceImpl_GetDisplayMode,
7778 IWineD3DDeviceImpl_SetDisplayMode,
7779 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7780 IWineD3DDeviceImpl_GetRasterStatus,
7781 IWineD3DDeviceImpl_GetSwapChain,
7782 IWineD3DDeviceImpl_Reset,
7783 IWineD3DDeviceImpl_SetDialogBoxMode,
7784 IWineD3DDeviceImpl_SetCursorProperties,
7785 IWineD3DDeviceImpl_SetCursorPosition,
7786 IWineD3DDeviceImpl_ShowCursor,
7787 IWineD3DDeviceImpl_TestCooperativeLevel,
7788 /*** Getters and setters **/
7789 IWineD3DDeviceImpl_SetClipPlane,
7790 IWineD3DDeviceImpl_GetClipPlane,
7791 IWineD3DDeviceImpl_SetClipStatus,
7792 IWineD3DDeviceImpl_GetClipStatus,
7793 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7794 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7795 IWineD3DDeviceImpl_SetDepthStencilSurface,
7796 IWineD3DDeviceImpl_GetDepthStencilSurface,
7797 IWineD3DDeviceImpl_SetGammaRamp,
7798 IWineD3DDeviceImpl_GetGammaRamp,
7799 IWineD3DDeviceImpl_SetIndices,
7800 IWineD3DDeviceImpl_GetIndices,
7801 IWineD3DDeviceImpl_SetBaseVertexIndex,
7802 IWineD3DDeviceImpl_GetBaseVertexIndex,
7803 IWineD3DDeviceImpl_SetLight,
7804 IWineD3DDeviceImpl_GetLight,
7805 IWineD3DDeviceImpl_SetLightEnable,
7806 IWineD3DDeviceImpl_GetLightEnable,
7807 IWineD3DDeviceImpl_SetMaterial,
7808 IWineD3DDeviceImpl_GetMaterial,
7809 IWineD3DDeviceImpl_SetNPatchMode,
7810 IWineD3DDeviceImpl_GetNPatchMode,
7811 IWineD3DDeviceImpl_SetPaletteEntries,
7812 IWineD3DDeviceImpl_GetPaletteEntries,
7813 IWineD3DDeviceImpl_SetPixelShader,
7814 IWineD3DDeviceImpl_GetPixelShader,
7815 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7816 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7817 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7818 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7819 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7820 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7821 IWineD3DDeviceImpl_SetRenderState,
7822 IWineD3DDeviceImpl_GetRenderState,
7823 IWineD3DDeviceImpl_SetRenderTarget,
7824 IWineD3DDeviceImpl_GetRenderTarget,
7825 IWineD3DDeviceImpl_SetFrontBackBuffers,
7826 IWineD3DDeviceImpl_SetSamplerState,
7827 IWineD3DDeviceImpl_GetSamplerState,
7828 IWineD3DDeviceImpl_SetScissorRect,
7829 IWineD3DDeviceImpl_GetScissorRect,
7830 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7831 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7832 IWineD3DDeviceImpl_SetStreamSource,
7833 IWineD3DDeviceImpl_GetStreamSource,
7834 IWineD3DDeviceImpl_SetStreamSourceFreq,
7835 IWineD3DDeviceImpl_GetStreamSourceFreq,
7836 IWineD3DDeviceImpl_SetTexture,
7837 IWineD3DDeviceImpl_GetTexture,
7838 IWineD3DDeviceImpl_SetTextureStageState,
7839 IWineD3DDeviceImpl_GetTextureStageState,
7840 IWineD3DDeviceImpl_SetTransform,
7841 IWineD3DDeviceImpl_GetTransform,
7842 IWineD3DDeviceImpl_SetVertexDeclaration,
7843 IWineD3DDeviceImpl_GetVertexDeclaration,
7844 IWineD3DDeviceImpl_SetVertexShader,
7845 IWineD3DDeviceImpl_GetVertexShader,
7846 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7847 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7848 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7849 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7850 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7851 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7852 IWineD3DDeviceImpl_SetViewport,
7853 IWineD3DDeviceImpl_GetViewport,
7854 IWineD3DDeviceImpl_MultiplyTransform,
7855 IWineD3DDeviceImpl_ValidateDevice,
7856 IWineD3DDeviceImpl_ProcessVertices,
7857 /*** State block ***/
7858 IWineD3DDeviceImpl_BeginStateBlock,
7859 IWineD3DDeviceImpl_EndStateBlock,
7860 /*** Scene management ***/
7861 IWineD3DDeviceImpl_BeginScene,
7862 IWineD3DDeviceImpl_EndScene,
7863 IWineD3DDeviceImpl_Present,
7864 IWineD3DDeviceImpl_Clear,
7865 IWineD3DDeviceImpl_ClearRendertargetView,
7867 IWineD3DDeviceImpl_SetPrimitiveType,
7868 IWineD3DDeviceImpl_GetPrimitiveType,
7869 IWineD3DDeviceImpl_DrawPrimitive,
7870 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7871 IWineD3DDeviceImpl_DrawPrimitiveUP,
7872 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7873 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7874 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7875 IWineD3DDeviceImpl_DrawRectPatch,
7876 IWineD3DDeviceImpl_DrawTriPatch,
7877 IWineD3DDeviceImpl_DeletePatch,
7878 IWineD3DDeviceImpl_ColorFill,
7879 IWineD3DDeviceImpl_UpdateTexture,
7880 IWineD3DDeviceImpl_UpdateSurface,
7881 IWineD3DDeviceImpl_GetFrontBufferData,
7882 /*** object tracking ***/
7883 IWineD3DDeviceImpl_ResourceReleased,
7884 IWineD3DDeviceImpl_EnumResources
7887 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7888 WINED3DRS_ALPHABLENDENABLE ,
7889 WINED3DRS_ALPHAFUNC ,
7890 WINED3DRS_ALPHAREF ,
7891 WINED3DRS_ALPHATESTENABLE ,
7893 WINED3DRS_COLORWRITEENABLE ,
7894 WINED3DRS_DESTBLEND ,
7895 WINED3DRS_DITHERENABLE ,
7896 WINED3DRS_FILLMODE ,
7897 WINED3DRS_FOGDENSITY ,
7899 WINED3DRS_FOGSTART ,
7900 WINED3DRS_LASTPIXEL ,
7901 WINED3DRS_SHADEMODE ,
7902 WINED3DRS_SRCBLEND ,
7903 WINED3DRS_STENCILENABLE ,
7904 WINED3DRS_STENCILFAIL ,
7905 WINED3DRS_STENCILFUNC ,
7906 WINED3DRS_STENCILMASK ,
7907 WINED3DRS_STENCILPASS ,
7908 WINED3DRS_STENCILREF ,
7909 WINED3DRS_STENCILWRITEMASK ,
7910 WINED3DRS_STENCILZFAIL ,
7911 WINED3DRS_TEXTUREFACTOR ,
7922 WINED3DRS_ZWRITEENABLE
7925 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7926 WINED3DTSS_ALPHAARG0 ,
7927 WINED3DTSS_ALPHAARG1 ,
7928 WINED3DTSS_ALPHAARG2 ,
7929 WINED3DTSS_ALPHAOP ,
7930 WINED3DTSS_BUMPENVLOFFSET ,
7931 WINED3DTSS_BUMPENVLSCALE ,
7932 WINED3DTSS_BUMPENVMAT00 ,
7933 WINED3DTSS_BUMPENVMAT01 ,
7934 WINED3DTSS_BUMPENVMAT10 ,
7935 WINED3DTSS_BUMPENVMAT11 ,
7936 WINED3DTSS_COLORARG0 ,
7937 WINED3DTSS_COLORARG1 ,
7938 WINED3DTSS_COLORARG2 ,
7939 WINED3DTSS_COLOROP ,
7940 WINED3DTSS_RESULTARG ,
7941 WINED3DTSS_TEXCOORDINDEX ,
7942 WINED3DTSS_TEXTURETRANSFORMFLAGS
7945 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7946 WINED3DSAMP_ADDRESSU ,
7947 WINED3DSAMP_ADDRESSV ,
7948 WINED3DSAMP_ADDRESSW ,
7949 WINED3DSAMP_BORDERCOLOR ,
7950 WINED3DSAMP_MAGFILTER ,
7951 WINED3DSAMP_MINFILTER ,
7952 WINED3DSAMP_MIPFILTER ,
7953 WINED3DSAMP_MIPMAPLODBIAS ,
7954 WINED3DSAMP_MAXMIPLEVEL ,
7955 WINED3DSAMP_MAXANISOTROPY ,
7956 WINED3DSAMP_SRGBTEXTURE ,
7957 WINED3DSAMP_ELEMENTINDEX
7960 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7962 WINED3DRS_AMBIENTMATERIALSOURCE ,
7963 WINED3DRS_CLIPPING ,
7964 WINED3DRS_CLIPPLANEENABLE ,
7965 WINED3DRS_COLORVERTEX ,
7966 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7967 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7968 WINED3DRS_FOGDENSITY ,
7970 WINED3DRS_FOGSTART ,
7971 WINED3DRS_FOGTABLEMODE ,
7972 WINED3DRS_FOGVERTEXMODE ,
7973 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7974 WINED3DRS_LIGHTING ,
7975 WINED3DRS_LOCALVIEWER ,
7976 WINED3DRS_MULTISAMPLEANTIALIAS ,
7977 WINED3DRS_MULTISAMPLEMASK ,
7978 WINED3DRS_NORMALIZENORMALS ,
7979 WINED3DRS_PATCHEDGESTYLE ,
7980 WINED3DRS_POINTSCALE_A ,
7981 WINED3DRS_POINTSCALE_B ,
7982 WINED3DRS_POINTSCALE_C ,
7983 WINED3DRS_POINTSCALEENABLE ,
7984 WINED3DRS_POINTSIZE ,
7985 WINED3DRS_POINTSIZE_MAX ,
7986 WINED3DRS_POINTSIZE_MIN ,
7987 WINED3DRS_POINTSPRITEENABLE ,
7988 WINED3DRS_RANGEFOGENABLE ,
7989 WINED3DRS_SPECULARMATERIALSOURCE ,
7990 WINED3DRS_TWEENFACTOR ,
7991 WINED3DRS_VERTEXBLEND ,
7992 WINED3DRS_CULLMODE ,
7996 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7997 WINED3DTSS_TEXCOORDINDEX ,
7998 WINED3DTSS_TEXTURETRANSFORMFLAGS
8001 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8002 WINED3DSAMP_DMAPOFFSET
8005 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8006 DWORD rep = This->StateTable[state].representative;
8010 WineD3DContext *context;
8013 for(i = 0; i < This->numContexts; i++) {
8014 context = This->contexts[i];
8015 if(isStateDirty(context, rep)) continue;
8017 context->dirtyArray[context->numDirtyEntries++] = rep;
8020 context->isStateDirty[idx] |= (1 << shift);
8024 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8025 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8026 /* The drawable size of a pbuffer render target is the current pbuffer size
8028 *width = dev->pbufferWidth;
8029 *height = dev->pbufferHeight;
8032 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8033 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8035 *width = This->pow2Width;
8036 *height = This->pow2Height;
8039 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8040 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8041 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8042 * current context's drawable, which is the size of the back buffer of the swapchain
8043 * the active context belongs to. The back buffer of the swapchain is stored as the
8044 * surface the context belongs to.
8046 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8047 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;