wined3d: Move WINED3DTS_TEXTURETRANSFORMFLAGS to the state table.
[wine.git] / dlls / wined3d / device.c
blobb68c4a22f0798c7585390eea9ca14c15b1e0a884
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
82 /* helper macros */
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
91 object->ref = 1; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
100 object->ref = 1; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
122 *pp##type = NULL; \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
131 *pp##type = NULL; \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * Utility functions follow
153 **********************************************************/
154 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
155 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
157 float quad_att;
158 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
162 glMatrixMode(GL_MODELVIEW);
163 glPushMatrix();
164 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
166 /* Diffuse: */
167 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
168 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
169 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
170 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
171 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
172 checkGLcall("glLightfv");
174 /* Specular */
175 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
176 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
177 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
178 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
179 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
180 checkGLcall("glLightfv");
182 /* Ambient */
183 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
184 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
185 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
186 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
187 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
188 checkGLcall("glLightfv");
190 /* Attenuation - Are these right? guessing... */
191 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
192 checkGLcall("glLightf");
193 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
194 checkGLcall("glLightf");
196 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
197 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
198 } else {
199 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
202 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
203 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
204 checkGLcall("glLightf");
206 switch (lightInfo->OriginalParms.Type) {
207 case WINED3DLIGHT_POINT:
208 /* Position */
209 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
210 checkGLcall("glLightfv");
211 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
212 checkGLcall("glLightf");
213 /* FIXME: Range */
214 break;
216 case WINED3DLIGHT_SPOT:
217 /* Position */
218 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
219 checkGLcall("glLightfv");
220 /* Direction */
221 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
222 checkGLcall("glLightfv");
223 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
224 checkGLcall("glLightf");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
226 checkGLcall("glLightf");
227 /* FIXME: Range */
228 break;
230 case WINED3DLIGHT_DIRECTIONAL:
231 /* Direction */
232 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
233 checkGLcall("glLightfv");
234 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
235 checkGLcall("glLightf");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
237 checkGLcall("glLightf");
238 break;
240 default:
241 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
244 /* Restore the modelview matrix */
245 glPopMatrix();
248 /**********************************************************
249 * GLSL helper functions follow
250 **********************************************************/
252 /** Detach the GLSL pixel or vertex shader object from the shader program */
253 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
257 if (shaderObj != 0 && programId != 0) {
258 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
259 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
260 checkGLcall("glDetachObjectARB");
264 /** Delete a GLSL shader program */
265 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
269 if (obj != 0) {
270 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
271 GL_EXTCALL(glDeleteObjectARB(obj));
272 checkGLcall("glDeleteObjectARB");
276 /** Delete the list of linked programs this shader is associated with.
277 * Also at this point, check to see if there are any objects left attached
278 * to each GLSL program. If not, delete the GLSL program object.
279 * This will be run when a device is released. */
280 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
282 struct list *ptr = NULL;
283 struct glsl_shader_prog_link *curLink = NULL;
284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
286 int numAttached = 0;
287 int i;
288 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
289 (one pixel shader and one vertex shader at most) */
291 ptr = list_head( &This->glsl_shader_progs );
292 while (ptr) {
293 /* First, get the current item,
294 * save the link to the next pointer,
295 * detach and delete shader objects,
296 * then de-allocate the list item's memory */
297 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
298 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* See if this object is still attached to the program - it may have been detached already */
301 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
302 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
303 for (i = 0; i < numAttached; i++) {
304 detach_glsl_shader(iface, objList[i], curLink->programId);
307 delete_glsl_shader_program(iface, curLink->programId);
309 /* Free the uniform locations */
310 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
311 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
313 /* Free the memory for this list item */
314 HeapFree(GetProcessHeap(), 0, curLink);
319 /* Apply the current values to the specified texture stage */
320 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
322 float col[4];
324 union {
325 float f;
326 DWORD d;
327 } tmpvalue;
329 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
330 clamping, MIPLOD, etc. This will work for up to 16 samplers.
333 if (Sampler >= GL_LIMITS(sampler_stages)) {
334 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
335 return;
337 VTRACE(("Activating appropriate texture state %d\n", Sampler));
338 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
339 ENTER_GL();
340 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
341 checkGLcall("glActiveTextureARB");
342 LEAVE_GL();
343 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
344 } else if (Sampler > 0) {
345 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
346 return;
349 /* TODO: change this to a lookup table
350 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
351 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
352 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
353 especially when there are a number of groups of states. */
355 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
357 /* apply any sampler states that always need applying */
358 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
359 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
360 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
361 GL_TEXTURE_LOD_BIAS_EXT,
362 tmpvalue.f);
363 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
366 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
367 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
368 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
370 /* TODO: NV_POINT_SPRITE */
371 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
372 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
373 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
374 glDisable(GL_POINT_SMOOTH);
376 /* Centre the texture on the vertex */
377 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
378 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
380 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
381 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
382 checkGLcall("glTexEnvf(...)");
383 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
384 glEnable( GL_POINT_SPRITE_ARB );
385 checkGLcall("glEnable(...)");
386 } else {
387 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
388 glDisable( GL_POINT_SPRITE_ARB );
389 checkGLcall("glEnable(...)");
393 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
396 /**********************************************************
397 * IUnknown parts follows
398 **********************************************************/
400 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
404 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
405 if (IsEqualGUID(riid, &IID_IUnknown)
406 || IsEqualGUID(riid, &IID_IWineD3DBase)
407 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
408 IUnknown_AddRef(iface);
409 *ppobj = This;
410 return S_OK;
412 *ppobj = NULL;
413 return E_NOINTERFACE;
416 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
418 ULONG refCount = InterlockedIncrement(&This->ref);
420 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
421 return refCount;
424 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
426 ULONG refCount = InterlockedDecrement(&This->ref);
428 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
430 if (!refCount) {
431 if (This->fbo) {
432 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
435 HeapFree(GetProcessHeap(), 0, This->render_targets);
437 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
439 /* TODO: Clean up all the surfaces and textures! */
440 /* NOTE: You must release the parent if the object was created via a callback
441 ** ***************************/
443 /* Delete any GLSL shader programs that may exist */
444 if (This->vs_selected_mode == SHADER_GLSL ||
445 This->ps_selected_mode == SHADER_GLSL)
446 delete_glsl_shader_list(iface);
448 /* Release the update stateblock */
449 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
450 if(This->updateStateBlock != This->stateBlock)
451 FIXME("(%p) Something's still holding the Update stateblock\n",This);
453 This->updateStateBlock = NULL;
454 { /* because were not doing proper internal refcounts releasing the primary state block
455 causes recursion with the extra checks in ResourceReleased, to avoid this we have
456 to set this->stateBlock = NULL; first */
457 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
458 This->stateBlock = NULL;
460 /* Release the stateblock */
461 if(IWineD3DStateBlock_Release(stateBlock) > 0){
462 FIXME("(%p) Something's still holding the Update stateblock\n",This);
466 if (This->resources != NULL ) {
467 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
468 dumpResources(This->resources);
472 IWineD3D_Release(This->wineD3D);
473 This->wineD3D = NULL;
474 HeapFree(GetProcessHeap(), 0, This);
475 TRACE("Freed device %p\n", This);
476 This = NULL;
478 return refCount;
481 /**********************************************************
482 * IWineD3DDevice implementation follows
483 **********************************************************/
484 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486 *pParent = This->parent;
487 IUnknown_AddRef(This->parent);
488 return WINED3D_OK;
491 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
492 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
493 GLenum error, glUsage;
494 DWORD vboUsage = object->resource.usage;
495 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
496 WARN("Creating a vbo failed once, not trying again\n");
497 return;
500 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
502 ENTER_GL();
503 /* Make sure that the gl error is cleared. Do not use checkGLcall
504 * here because checkGLcall just prints a fixme and continues. However,
505 * if an error during VBO creation occurs we can fall back to non-vbo operation
506 * with full functionality(but performance loss)
508 while(glGetError() != GL_NO_ERROR);
510 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
511 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
512 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
513 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
514 * to check if the rhw and color values are in the correct format.
517 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
518 error = glGetError();
519 if(object->vbo == 0 || error != GL_NO_ERROR) {
520 WARN("Failed to create a VBO with error %d\n", error);
521 goto error;
524 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
525 error = glGetError();
526 if(error != GL_NO_ERROR) {
527 WARN("Failed to bind the VBO, error %d\n", error);
528 goto error;
531 /* Transformed vertices are horribly inflexible. If the app specifies an
532 * vertex buffer with transformed vertices in default pool without DYNAMIC
533 * usage assume DYNAMIC usage and print a warning. The app will have to update
534 * the vertices regularily for them to be useful
536 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
537 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
538 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
539 vboUsage |= WINED3DUSAGE_DYNAMIC;
542 /* Don't use static, because dx apps tend to update the buffer
543 * quite often even if they specify 0 usage
545 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
546 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
547 TRACE("Gl usage = GL_STREAM_DRAW\n");
548 glUsage = GL_STREAM_DRAW_ARB;
549 break;
550 case D3DUSAGE_WRITEONLY:
551 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
552 glUsage = GL_DYNAMIC_DRAW_ARB;
553 break;
554 case D3DUSAGE_DYNAMIC:
555 TRACE("Gl usage = GL_STREAM_COPY\n");
556 glUsage = GL_STREAM_COPY_ARB;
557 break;
558 default:
559 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
560 glUsage = GL_DYNAMIC_COPY_ARB;
561 break;
564 /* Reserve memory for the buffer. The amount of data won't change
565 * so we are safe with calling glBufferData once with a NULL ptr and
566 * calling glBufferSubData on updates
568 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
569 error = glGetError();
570 if(error != GL_NO_ERROR) {
571 WARN("glBufferDataARB failed with error %d\n", error);
572 goto error;
575 LEAVE_GL();
577 return;
578 error:
579 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
580 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
581 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
582 object->vbo = 0;
583 object->Flags |= VBFLAG_VBOCREATEFAIL;
584 LEAVE_GL();
585 return;
588 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
589 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
590 IUnknown *parent) {
591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
592 IWineD3DVertexBufferImpl *object;
593 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
594 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
595 BOOL conv;
596 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
598 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
599 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
601 if(Size == 0) return WINED3DERR_INVALIDCALL;
603 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
604 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
606 object->fvf = FVF;
608 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
609 * drawStridedFast (half-life 2).
611 * Basically converting the vertices in the buffer is quite expensive, and observations
612 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
613 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
615 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
616 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
617 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
618 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
619 * dx7 apps.
620 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
621 * more. In this call we can convert dx7 buffers too.
623 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
624 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
625 (dxVersion > 7 || !conv) ) {
626 CreateVBO(object);
628 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
629 if(dxVersion == 7 && object->vbo) {
630 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
631 object->resource.allocatedMemory = NULL;
635 return WINED3D_OK;
638 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
639 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
640 HANDLE *sharedHandle, IUnknown *parent) {
641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
642 IWineD3DIndexBufferImpl *object;
643 TRACE("(%p) Creating index buffer\n", This);
645 /* Allocate the storage for the device */
646 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
648 /*TODO: use VBO's */
649 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
650 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
653 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
654 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
655 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
657 return WINED3D_OK;
660 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
663 IWineD3DStateBlockImpl *object;
664 int i, j;
665 HRESULT temp_result;
667 D3DCREATEOBJECTINSTANCE(object, StateBlock)
668 object->blockType = Type;
670 /* Special case - Used during initialization to produce a placeholder stateblock
671 so other functions called can update a state block */
672 if (Type == WINED3DSBT_INIT) {
673 /* Don't bother increasing the reference count otherwise a device will never
674 be freed due to circular dependencies */
675 return WINED3D_OK;
678 temp_result = allocate_shader_constants(object);
679 if (WINED3D_OK != temp_result)
680 return temp_result;
682 /* Otherwise, might as well set the whole state block to the appropriate values */
683 if (This->stateBlock != NULL)
684 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
685 else
686 memset(object->streamFreq, 1, sizeof(object->streamFreq));
688 /* Reset the ref and type after kludging it */
689 object->wineD3DDevice = This;
690 object->ref = 1;
691 object->blockType = Type;
693 TRACE("Updating changed flags appropriate for type %d\n", Type);
695 if (Type == WINED3DSBT_ALL) {
697 TRACE("ALL => Pretend everything has changed\n");
698 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
700 } else if (Type == WINED3DSBT_PIXELSTATE) {
702 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
703 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
705 object->changed.pixelShader = TRUE;
707 /* Pixel Shader Constants */
708 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
709 object->changed.pixelShaderConstantsF[i] = TRUE;
710 for (i = 0; i < MAX_CONST_B; ++i)
711 object->changed.pixelShaderConstantsB[i] = TRUE;
712 for (i = 0; i < MAX_CONST_I; ++i)
713 object->changed.pixelShaderConstantsI[i] = TRUE;
715 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
716 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
718 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
719 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
720 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
723 for (j = 0 ; j < 16; j++) {
724 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
726 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
730 } else if (Type == WINED3DSBT_VERTEXSTATE) {
732 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
733 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
735 object->changed.vertexShader = TRUE;
737 /* Vertex Shader Constants */
738 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
739 object->changed.vertexShaderConstantsF[i] = TRUE;
740 for (i = 0; i < MAX_CONST_B; ++i)
741 object->changed.vertexShaderConstantsB[i] = TRUE;
742 for (i = 0; i < MAX_CONST_I; ++i)
743 object->changed.vertexShaderConstantsI[i] = TRUE;
745 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
746 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
748 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
749 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
750 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
753 for (j = 0 ; j < 16; j++){
754 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
755 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
759 /* Duplicate light chain */
761 PLIGHTINFOEL *src = NULL;
762 PLIGHTINFOEL *dst = NULL;
763 PLIGHTINFOEL *newEl = NULL;
764 src = This->stateBlock->lights;
765 object->lights = NULL;
768 while (src) {
769 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
770 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
771 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
772 newEl->prev = dst;
773 newEl->changed = TRUE;
774 newEl->enabledChanged = TRUE;
775 if (dst == NULL) {
776 object->lights = newEl;
777 } else {
778 dst->next = newEl;
780 dst = newEl;
781 src = src->next;
786 } else {
787 FIXME("Unrecognized state block type %d\n", Type);
790 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
791 return WINED3D_OK;
795 /* ************************************
796 MSDN:
797 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
799 Discard
800 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
802 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
804 ******************************** */
806 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) {
807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
808 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
809 unsigned int pow2Width, pow2Height;
810 unsigned int Size = 1;
811 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
812 TRACE("(%p) Create surface\n",This);
814 /** FIXME: Check ranges on the inputs are valid
815 * MSDN
816 * MultisampleQuality
817 * [in] Quality level. The valid range is between zero and one less than the level
818 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
819 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
820 * values of paired render targets, depth stencil surfaces, and the MultiSample type
821 * must all match.
822 *******************************/
826 * TODO: Discard MSDN
827 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
829 * If this flag is set, the contents of the depth stencil buffer will be
830 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
831 * with a different depth surface.
833 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
834 ***************************/
836 if(MultisampleQuality < 0) {
837 FIXME("Invalid multisample level %d\n", MultisampleQuality);
838 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
841 if(MultisampleQuality > 0) {
842 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
843 MultisampleQuality=0;
846 /** FIXME: Check that the format is supported
847 * by the device.
848 *******************************/
850 /* Non-power2 support */
851 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
852 pow2Width = Width;
853 pow2Height = Height;
854 } else {
855 /* Find the nearest pow2 match */
856 pow2Width = pow2Height = 1;
857 while (pow2Width < Width) pow2Width <<= 1;
858 while (pow2Height < Height) pow2Height <<= 1;
861 if (pow2Width > Width || pow2Height > Height) {
862 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
863 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
864 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
865 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
866 This, Width, Height);
867 return WINED3DERR_NOTAVAILABLE;
871 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
872 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
873 * space!
874 *********************************/
875 if (WINED3DFMT_UNKNOWN == Format) {
876 Size = 0;
877 } else if (Format == WINED3DFMT_DXT1) {
878 /* DXT1 is half byte per pixel */
879 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
881 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
882 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
883 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
884 } else {
885 /* The pitch is a multiple of 4 bytes */
886 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
887 Size *= pow2Height;
890 /** Create and initialise the surface resource **/
891 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
892 /* "Standalone" surface */
893 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
895 object->currentDesc.Width = Width;
896 object->currentDesc.Height = Height;
897 object->currentDesc.MultiSampleType = MultiSample;
898 object->currentDesc.MultiSampleQuality = MultisampleQuality;
900 /* Setup some glformat defaults */
901 object->glDescription.glFormat = tableEntry->glFormat;
902 object->glDescription.glFormatInternal = tableEntry->glInternal;
903 object->glDescription.glType = tableEntry->glType;
905 object->glDescription.textureName = 0;
906 object->glDescription.level = Level;
907 object->glDescription.target = GL_TEXTURE_2D;
909 /* Internal data */
910 object->pow2Width = pow2Width;
911 object->pow2Height = pow2Height;
913 /* Flags */
914 object->Flags = 0; /* We start without flags set */
915 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
916 object->Flags |= Discard ? SFLAG_DISCARD : 0;
917 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
918 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
921 if (WINED3DFMT_UNKNOWN != Format) {
922 object->bytesPerPixel = tableEntry->bpp;
923 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
924 object->pow2Size *= pow2Height;
925 } else {
926 object->bytesPerPixel = 0;
927 object->pow2Size = 0;
930 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
932 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
934 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
935 * this function is too deep to need to care about things like this.
936 * Levels need to be checked too, and possibly Type since they all affect what can be done.
937 * ****************************************/
938 switch(Pool) {
939 case WINED3DPOOL_SCRATCH:
940 if(!Lockable)
941 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
942 which are mutually exclusive, setting lockable to true\n");
943 Lockable = TRUE;
944 break;
945 case WINED3DPOOL_SYSTEMMEM:
946 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
947 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
948 case WINED3DPOOL_MANAGED:
949 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
950 Usage of DYNAMIC which are mutually exclusive, not doing \
951 anything just telling you.\n");
952 break;
953 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
954 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
955 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
956 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
957 break;
958 default:
959 FIXME("(%p) Unknown pool %d\n", This, Pool);
960 break;
963 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
964 FIXME("Trying to create a render target that isn't in the default pool\n");
967 /* mark the texture as dirty so that it gets loaded first time around*/
968 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
969 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
970 This, Width, Height, Format, debug_d3dformat(Format),
971 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
973 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
974 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
975 This->ddraw_primary = (IWineD3DSurface *) object;
977 /* Look at the implementation and set the correct Vtable */
978 switch(Impl) {
979 case SURFACE_OPENGL:
980 /* Nothing to do, it's set already */
981 break;
983 case SURFACE_GDI:
984 object->lpVtbl = &IWineGDISurface_Vtbl;
985 break;
987 default:
988 /* To be sure to catch this */
989 ERR("Unknown requested surface implementation %d!\n", Impl);
990 IWineD3DSurface_Release((IWineD3DSurface *) object);
991 return WINED3DERR_INVALIDCALL;
994 /* Call the private setup routine */
995 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
999 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1000 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1002 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1005 IWineD3DTextureImpl *object;
1006 unsigned int i;
1007 UINT tmpW;
1008 UINT tmpH;
1009 HRESULT hr;
1010 unsigned int pow2Width;
1011 unsigned int pow2Height;
1014 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1015 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1016 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1018 /* TODO: It should only be possible to create textures for formats
1019 that are reported as supported */
1020 if (WINED3DFMT_UNKNOWN >= Format) {
1021 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1022 return WINED3DERR_INVALIDCALL;
1025 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1026 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1027 object->width = Width;
1028 object->height = Height;
1030 /** Non-power2 support **/
1031 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1032 pow2Width = Width;
1033 pow2Height = Height;
1034 } else {
1035 /* Find the nearest pow2 match */
1036 pow2Width = pow2Height = 1;
1037 while (pow2Width < Width) pow2Width <<= 1;
1038 while (pow2Height < Height) pow2Height <<= 1;
1041 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1042 /* Precalculated scaling for 'faked' non power of two texture coords */
1043 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1044 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1045 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1047 /* Calculate levels for mip mapping */
1048 if (Levels == 0) {
1049 TRACE("calculating levels %d\n", object->baseTexture.levels);
1050 object->baseTexture.levels++;
1051 tmpW = Width;
1052 tmpH = Height;
1053 while (tmpW > 1 || tmpH > 1) {
1054 tmpW = max(1, tmpW >> 1);
1055 tmpH = max(1, tmpH >> 1);
1056 object->baseTexture.levels++;
1058 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1061 /* Generate all the surfaces */
1062 tmpW = Width;
1063 tmpH = Height;
1064 for (i = 0; i < object->baseTexture.levels; i++)
1066 /* use the callback to create the texture surface */
1067 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1068 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1069 FIXME("Failed to create surface %p\n", object);
1070 /* clean up */
1071 object->surfaces[i] = NULL;
1072 IWineD3DTexture_Release((IWineD3DTexture *)object);
1074 *ppTexture = NULL;
1075 return hr;
1078 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1079 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1080 /* calculate the next mipmap level */
1081 tmpW = max(1, tmpW >> 1);
1082 tmpH = max(1, tmpH >> 1);
1085 TRACE("(%p) : Created texture %p\n", This, object);
1086 return WINED3D_OK;
1089 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1090 UINT Width, UINT Height, UINT Depth,
1091 UINT Levels, DWORD Usage,
1092 WINED3DFORMAT Format, WINED3DPOOL Pool,
1093 IWineD3DVolumeTexture **ppVolumeTexture,
1094 HANDLE *pSharedHandle, IUnknown *parent,
1095 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1098 IWineD3DVolumeTextureImpl *object;
1099 unsigned int i;
1100 UINT tmpW;
1101 UINT tmpH;
1102 UINT tmpD;
1104 /* TODO: It should only be possible to create textures for formats
1105 that are reported as supported */
1106 if (WINED3DFMT_UNKNOWN >= Format) {
1107 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1108 return WINED3DERR_INVALIDCALL;
1111 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1112 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1114 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1115 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1117 object->width = Width;
1118 object->height = Height;
1119 object->depth = Depth;
1121 /* Calculate levels for mip mapping */
1122 if (Levels == 0) {
1123 object->baseTexture.levels++;
1124 tmpW = Width;
1125 tmpH = Height;
1126 tmpD = Depth;
1127 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1128 tmpW = max(1, tmpW >> 1);
1129 tmpH = max(1, tmpH >> 1);
1130 tmpD = max(1, tmpD >> 1);
1131 object->baseTexture.levels++;
1133 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1136 /* Generate all the surfaces */
1137 tmpW = Width;
1138 tmpH = Height;
1139 tmpD = Depth;
1141 for (i = 0; i < object->baseTexture.levels; i++)
1143 /* Create the volume */
1144 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1145 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1147 /* Set its container to this object */
1148 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1150 /* calcualte the next mipmap level */
1151 tmpW = max(1, tmpW >> 1);
1152 tmpH = max(1, tmpH >> 1);
1153 tmpD = max(1, tmpD >> 1);
1156 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1157 TRACE("(%p) : Created volume texture %p\n", This, object);
1158 return WINED3D_OK;
1161 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1162 UINT Width, UINT Height, UINT Depth,
1163 DWORD Usage,
1164 WINED3DFORMAT Format, WINED3DPOOL Pool,
1165 IWineD3DVolume** ppVolume,
1166 HANDLE* pSharedHandle, IUnknown *parent) {
1168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1169 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1170 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1172 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1174 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1175 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1177 object->currentDesc.Width = Width;
1178 object->currentDesc.Height = Height;
1179 object->currentDesc.Depth = Depth;
1180 object->bytesPerPixel = formatDesc->bpp;
1182 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1183 object->lockable = TRUE;
1184 object->locked = FALSE;
1185 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1186 object->dirty = TRUE;
1188 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1191 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1192 UINT Levels, DWORD Usage,
1193 WINED3DFORMAT Format, WINED3DPOOL Pool,
1194 IWineD3DCubeTexture **ppCubeTexture,
1195 HANDLE *pSharedHandle, IUnknown *parent,
1196 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1199 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1200 unsigned int i, j;
1201 UINT tmpW;
1202 HRESULT hr;
1203 unsigned int pow2EdgeLength = EdgeLength;
1205 /* TODO: It should only be possible to create textures for formats
1206 that are reported as supported */
1207 if (WINED3DFMT_UNKNOWN >= Format) {
1208 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1209 return WINED3DERR_INVALIDCALL;
1212 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1213 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1215 TRACE("(%p) Create Cube Texture\n", This);
1217 /** Non-power2 support **/
1219 /* Find the nearest pow2 match */
1220 pow2EdgeLength = 1;
1221 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1223 object->edgeLength = EdgeLength;
1224 /* TODO: support for native non-power 2 */
1225 /* Precalculated scaling for 'faked' non power of two texture coords */
1226 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1228 /* Calculate levels for mip mapping */
1229 if (Levels == 0) {
1230 object->baseTexture.levels++;
1231 tmpW = EdgeLength;
1232 while (tmpW > 1) {
1233 tmpW = max(1, tmpW >> 1);
1234 object->baseTexture.levels++;
1236 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1239 /* Generate all the surfaces */
1240 tmpW = EdgeLength;
1241 for (i = 0; i < object->baseTexture.levels; i++) {
1243 /* Create the 6 faces */
1244 for (j = 0; j < 6; j++) {
1246 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1247 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1249 if(hr!= WINED3D_OK) {
1250 /* clean up */
1251 int k;
1252 int l;
1253 for (l = 0; l < j; l++) {
1254 IWineD3DSurface_Release(object->surfaces[j][i]);
1256 for (k = 0; k < i; k++) {
1257 for (l = 0; l < 6; l++) {
1258 IWineD3DSurface_Release(object->surfaces[l][j]);
1262 FIXME("(%p) Failed to create surface\n",object);
1263 HeapFree(GetProcessHeap(),0,object);
1264 *ppCubeTexture = NULL;
1265 return hr;
1267 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1268 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1270 tmpW = max(1, tmpW >> 1);
1273 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1274 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1275 return WINED3D_OK;
1278 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1280 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1282 if (NULL == ppQuery) {
1283 /* Just a check to see if we support this type of query */
1284 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1285 switch(Type) {
1286 case WINED3DQUERYTYPE_OCCLUSION:
1287 TRACE("(%p) occlusion query\n", This);
1288 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1289 hr = WINED3D_OK;
1290 else
1291 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1292 break;
1293 case WINED3DQUERYTYPE_VCACHE:
1294 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1295 case WINED3DQUERYTYPE_VERTEXSTATS:
1296 case WINED3DQUERYTYPE_EVENT:
1297 case WINED3DQUERYTYPE_TIMESTAMP:
1298 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1299 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1300 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1301 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1302 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1303 case WINED3DQUERYTYPE_PIXELTIMINGS:
1304 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1305 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1306 default:
1307 FIXME("(%p) Unhandled query type %d\n", This, Type);
1309 return hr;
1312 D3DCREATEOBJECTINSTANCE(object, Query)
1313 object->type = Type;
1314 /* allocated the 'extended' data based on the type of query requested */
1315 switch(Type){
1316 case WINED3DQUERYTYPE_OCCLUSION:
1317 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1318 TRACE("(%p) Allocating data for an occlusion query\n", This);
1319 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1320 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1321 break;
1323 case WINED3DQUERYTYPE_VCACHE:
1324 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1325 case WINED3DQUERYTYPE_VERTEXSTATS:
1326 case WINED3DQUERYTYPE_EVENT:
1327 case WINED3DQUERYTYPE_TIMESTAMP:
1328 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1329 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1330 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1331 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1332 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1333 case WINED3DQUERYTYPE_PIXELTIMINGS:
1334 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1335 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1336 default:
1337 object->extendedData = 0;
1338 FIXME("(%p) Unhandled query type %d\n",This , Type);
1340 TRACE("(%p) : Created Query %p\n", This, object);
1341 return WINED3D_OK;
1344 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1345 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1346 IUnknown* parent,
1347 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1348 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1351 HDC hDc;
1352 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1353 int num;
1354 XVisualInfo template;
1355 GLXContext oldContext;
1356 Drawable oldDrawable;
1357 HRESULT hr = WINED3D_OK;
1359 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1361 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1362 * does a device hold a reference to a swap chain giving them a lifetime of the device
1363 * or does the swap chain notify the device of its destruction.
1364 *******************************/
1366 /* Check the params */
1367 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1368 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1369 return WINED3DERR_INVALIDCALL;
1370 } else if (*pPresentationParameters->BackBufferCount > 1) {
1371 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");
1374 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1376 /*********************
1377 * Lookup the window Handle and the relating X window handle
1378 ********************/
1380 /* Setup hwnd we are using, plus which display this equates to */
1381 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1382 if (!object->win_handle) {
1383 object->win_handle = This->createParms.hFocusWindow;
1386 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1387 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1388 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1389 return WINED3DERR_NOTAVAILABLE;
1391 hDc = GetDC(object->win_handle);
1392 object->display = get_display(hDc);
1393 ReleaseDC(object->win_handle, hDc);
1394 TRACE("Using a display of %p %p\n", object->display, hDc);
1396 if (NULL == object->display || NULL == hDc) {
1397 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1398 return WINED3DERR_NOTAVAILABLE;
1401 if (object->win == 0) {
1402 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1403 return WINED3DERR_NOTAVAILABLE;
1406 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1407 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1410 * Create an opengl context for the display visual
1411 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1412 * use different properties after that point in time. FIXME: How to handle when requested format
1413 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1414 * it chooses is identical to the one already being used!
1415 **********************************/
1417 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1418 ENTER_GL();
1420 /* Create a new context for this swapchain */
1421 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1422 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1423 (or the best possible if none is requested) */
1424 TRACE("Found x visual ID : %ld\n", template.visualid);
1426 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1427 if (NULL == object->visInfo) {
1428 ERR("cannot really get XVisual\n");
1429 LEAVE_GL();
1430 return WINED3DERR_NOTAVAILABLE;
1431 } else {
1432 int n, value;
1433 /* Write out some debug info about the visual/s */
1434 TRACE("Using x visual ID : %ld\n", template.visualid);
1435 TRACE(" visual info: %p\n", object->visInfo);
1436 TRACE(" num items : %d\n", num);
1437 for (n = 0;n < num; n++) {
1438 TRACE("=====item=====: %d\n", n + 1);
1439 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1440 TRACE(" screen : %d\n", object->visInfo[n].screen);
1441 TRACE(" depth : %u\n", object->visInfo[n].depth);
1442 TRACE(" class : %d\n", object->visInfo[n].class);
1443 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1444 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1445 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1446 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1447 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1448 /* log some extra glx info */
1449 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1450 TRACE(" gl_aux_buffers : %d\n", value);
1451 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1452 TRACE(" gl_buffer_size : %d\n", value);
1453 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1454 TRACE(" gl_red_size : %d\n", value);
1455 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1456 TRACE(" gl_green_size : %d\n", value);
1457 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1458 TRACE(" gl_blue_size : %d\n", value);
1459 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1460 TRACE(" gl_alpha_size : %d\n", value);
1461 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1462 TRACE(" gl_depth_size : %d\n", value);
1463 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1464 TRACE(" gl_stencil_size : %d\n", value);
1466 /* Now choose a similar visual ID*/
1468 #ifdef USE_CONTEXT_MANAGER
1470 /** TODO: use a context mamager **/
1471 #endif
1474 IWineD3DSwapChain *implSwapChain;
1475 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1476 /* The first time around we create the context that is shared with all other swapchains and render targets */
1477 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1478 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1479 } else {
1481 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1482 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1483 /* and create a new context with the implicit swapchains context as the shared context */
1484 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1485 IWineD3DSwapChain_Release(implSwapChain);
1489 /* Cleanup */
1490 XFree(object->visInfo);
1491 object->visInfo = NULL;
1493 LEAVE_GL();
1495 if (!object->glCtx) {
1496 ERR("Failed to create GLX context\n");
1497 return WINED3DERR_NOTAVAILABLE;
1498 } else {
1499 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1500 object->win_handle, object->glCtx, object->win, object->visInfo);
1503 /*********************
1504 * Windowed / Fullscreen
1505 *******************/
1508 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1509 * so we should really check to see if there is a fullscreen swapchain already
1510 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1511 **************************************/
1513 if (!*(pPresentationParameters->Windowed)) {
1515 DEVMODEW devmode;
1516 HDC hdc;
1517 int bpp = 0;
1519 /* Get info on the current display setup */
1520 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1521 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1522 DeleteDC(hdc);
1524 /* Change the display settings */
1525 memset(&devmode, 0, sizeof(DEVMODEW));
1526 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1527 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1528 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1529 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1530 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1531 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1533 /* Make popup window */
1534 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1535 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1536 *(pPresentationParameters->BackBufferWidth),
1537 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1539 /* For GetDisplayMode */
1540 This->ddraw_width = devmode.dmPelsWidth;
1541 This->ddraw_height = devmode.dmPelsHeight;
1542 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1546 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1547 * then the corresponding dimension of the client area of the hDeviceWindow
1548 * (or the focus window, if hDeviceWindow is NULL) is taken.
1549 **********************/
1551 if (*(pPresentationParameters->Windowed) &&
1552 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1553 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1555 RECT Rect;
1556 GetClientRect(object->win_handle, &Rect);
1558 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1559 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1560 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1562 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1563 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1564 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1568 /*********************
1569 * finish off parameter initialization
1570 *******************/
1572 /* Put the correct figures in the presentation parameters */
1573 TRACE("Copying across presentation parameters\n");
1574 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1575 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1576 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1577 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1578 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1579 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1580 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1581 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1582 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1583 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1584 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1585 object->presentParms.Flags = *(pPresentationParameters->Flags);
1586 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1587 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1590 /*********************
1591 * Create the back, front and stencil buffers
1592 *******************/
1594 TRACE("calling rendertarget CB\n");
1595 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1596 parent,
1597 object->presentParms.BackBufferWidth,
1598 object->presentParms.BackBufferHeight,
1599 object->presentParms.BackBufferFormat,
1600 object->presentParms.MultiSampleType,
1601 object->presentParms.MultiSampleQuality,
1602 TRUE /* Lockable */,
1603 &object->frontBuffer,
1604 NULL /* pShared (always null)*/);
1605 if (object->frontBuffer != NULL)
1606 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1608 if(object->presentParms.BackBufferCount > 0) {
1609 int i;
1611 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1612 if(!object->backBuffer) {
1613 ERR("Out of memory\n");
1615 if (object->frontBuffer) {
1616 IUnknown *bufferParent;
1617 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1618 IUnknown_Release(bufferParent); /* once for the get parent */
1619 if (IUnknown_Release(bufferParent) > 0) {
1620 FIXME("(%p) Something's still holding the front buffer\n",This);
1623 HeapFree(GetProcessHeap(), 0, object);
1624 return E_OUTOFMEMORY;
1627 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1628 TRACE("calling rendertarget CB\n");
1629 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1630 parent,
1631 object->presentParms.BackBufferWidth,
1632 object->presentParms.BackBufferHeight,
1633 object->presentParms.BackBufferFormat,
1634 object->presentParms.MultiSampleType,
1635 object->presentParms.MultiSampleQuality,
1636 TRUE /* Lockable */,
1637 &object->backBuffer[i],
1638 NULL /* pShared (always null)*/);
1639 if(hr == WINED3D_OK && object->backBuffer[i]) {
1640 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1641 } else {
1642 break;
1645 } else {
1646 object->backBuffer = NULL;
1649 if (object->backBuffer != NULL) {
1650 ENTER_GL();
1651 glDrawBuffer(GL_BACK);
1652 checkGLcall("glDrawBuffer(GL_BACK)");
1653 LEAVE_GL();
1654 } else {
1655 /* Single buffering - draw to front buffer */
1656 ENTER_GL();
1657 glDrawBuffer(GL_FRONT);
1658 checkGLcall("glDrawBuffer(GL_FRONT)");
1659 LEAVE_GL();
1662 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1663 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1664 TRACE("Creating depth stencil buffer\n");
1665 if (This->depthStencilBuffer == NULL ) {
1666 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1667 parent,
1668 object->presentParms.BackBufferWidth,
1669 object->presentParms.BackBufferHeight,
1670 object->presentParms.AutoDepthStencilFormat,
1671 object->presentParms.MultiSampleType,
1672 object->presentParms.MultiSampleQuality,
1673 FALSE /* FIXME: Discard */,
1674 &This->depthStencilBuffer,
1675 NULL /* pShared (always null)*/ );
1676 if (This->depthStencilBuffer != NULL)
1677 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1680 /** TODO: A check on width, height and multisample types
1681 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1682 ****************************/
1683 object->wantsDepthStencilBuffer = TRUE;
1684 } else {
1685 object->wantsDepthStencilBuffer = FALSE;
1688 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1691 /*********************
1692 * init the default renderTarget management
1693 *******************/
1694 object->drawable = object->win;
1695 object->render_ctx = object->glCtx;
1697 if (hr == WINED3D_OK) {
1698 /*********************
1699 * Setup some defaults and clear down the buffers
1700 *******************/
1701 ENTER_GL();
1702 /** save current context and drawable **/
1703 oldContext = glXGetCurrentContext();
1704 oldDrawable = glXGetCurrentDrawable();
1706 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1707 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1708 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1710 checkGLcall("glXMakeCurrent");
1712 TRACE("Setting up the screen\n");
1713 /* Clear the screen */
1714 glClearColor(1.0, 0.0, 0.0, 0.0);
1715 checkGLcall("glClearColor");
1716 glClearIndex(0);
1717 glClearDepth(1);
1718 glClearStencil(0xffff);
1720 checkGLcall("glClear");
1722 glColor3f(1.0, 1.0, 1.0);
1723 checkGLcall("glColor3f");
1725 glEnable(GL_LIGHTING);
1726 checkGLcall("glEnable");
1728 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1729 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1731 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1732 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1734 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1735 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1737 /* switch back to the original context (if there was one)*/
1738 if (This->swapchains) {
1739 /** TODO: restore the context and drawable **/
1740 glXMakeCurrent(object->display, oldDrawable, oldContext);
1743 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1744 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1745 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1746 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1747 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1749 LEAVE_GL();
1751 TRACE("Set swapchain to %p\n", object);
1752 } else { /* something went wrong so clean up */
1753 IUnknown* bufferParent;
1754 if (object->frontBuffer) {
1756 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1757 IUnknown_Release(bufferParent); /* once for the get parent */
1758 if (IUnknown_Release(bufferParent) > 0) {
1759 FIXME("(%p) Something's still holding the front buffer\n",This);
1762 if (object->backBuffer) {
1763 int i;
1764 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1765 if(object->backBuffer[i]) {
1766 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1767 IUnknown_Release(bufferParent); /* once for the get parent */
1768 if (IUnknown_Release(bufferParent) > 0) {
1769 FIXME("(%p) Something's still holding the back buffer\n",This);
1773 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1774 object->backBuffer = NULL;
1776 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1777 /* Clean up the context */
1778 /* check that we are the current context first (we shouldn't be though!) */
1779 if (object->glCtx != 0) {
1780 if(glXGetCurrentContext() == object->glCtx) {
1781 glXMakeCurrent(object->display, None, NULL);
1783 glXDestroyContext(object->display, object->glCtx);
1785 HeapFree(GetProcessHeap(), 0, object);
1789 return hr;
1792 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1793 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1795 TRACE("(%p)\n", This);
1797 return This->NumberOfSwapChains;
1800 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1802 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1804 if(iSwapChain < This->NumberOfSwapChains) {
1805 *pSwapChain = This->swapchains[iSwapChain];
1806 IWineD3DSwapChain_AddRef(*pSwapChain);
1807 TRACE("(%p) returning %p\n", This, *pSwapChain);
1808 return WINED3D_OK;
1809 } else {
1810 TRACE("Swapchain out of range\n");
1811 *pSwapChain = NULL;
1812 return WINED3DERR_INVALIDCALL;
1816 /*****
1817 * Vertex Declaration
1818 *****/
1819 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 IWineD3DVertexDeclarationImpl *object = NULL;
1822 HRESULT hr = WINED3D_OK;
1823 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1824 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1825 object->allFVF = 0;
1827 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1829 return hr;
1832 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1833 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1835 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1836 HRESULT hr = WINED3D_OK;
1837 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1838 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1840 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1842 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1843 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1844 if (pDeclaration != NULL) {
1845 IWineD3DVertexDeclaration *vertexDeclaration;
1846 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1847 if (WINED3D_OK == hr) {
1848 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1849 object->vertexDeclaration = vertexDeclaration;
1850 } else {
1851 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1852 IWineD3DVertexShader_Release(*ppVertexShader);
1853 return WINED3DERR_INVALIDCALL;
1857 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1859 if (WINED3D_OK != hr) {
1860 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1861 IWineD3DVertexShader_Release(*ppVertexShader);
1862 return WINED3DERR_INVALIDCALL;
1865 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1866 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1867 /* Foo */
1868 } else {
1869 /* Bar */
1872 #endif
1874 return WINED3D_OK;
1877 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1880 HRESULT hr = WINED3D_OK;
1882 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1883 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1884 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1885 if (WINED3D_OK == hr) {
1886 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1887 } else {
1888 WARN("(%p) : Failed to create pixel shader\n", This);
1891 return hr;
1894 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1896 IWineD3DPaletteImpl *object;
1897 HRESULT hr;
1898 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1900 /* Create the new object */
1901 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1902 if(!object) {
1903 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1904 return E_OUTOFMEMORY;
1907 object->lpVtbl = &IWineD3DPalette_Vtbl;
1908 object->ref = 1;
1909 object->Flags = Flags;
1910 object->parent = Parent;
1911 object->wineD3DDevice = This;
1912 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1914 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1916 if(!object->hpal) {
1917 HeapFree( GetProcessHeap(), 0, object);
1918 return E_OUTOFMEMORY;
1921 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1922 if(FAILED(hr)) {
1923 IWineD3DPalette_Release((IWineD3DPalette *) object);
1924 return hr;
1927 *Palette = (IWineD3DPalette *) object;
1929 return WINED3D_OK;
1932 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1934 IWineD3DSwapChainImpl *swapchain;
1935 DWORD state;
1937 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1938 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1940 /* TODO: Test if OpenGL is compiled in and loaded */
1942 /* Initialize the texture unit mapping to a 1:1 mapping */
1943 for(state = 0; state < MAX_SAMPLERS; state++) {
1944 This->texUnitMap[state] = state;
1946 This->oneToOneTexUnitMap = TRUE;
1948 /* Setup the implicit swapchain */
1949 TRACE("Creating implicit swapchain\n");
1950 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1951 WARN("Failed to create implicit swapchain\n");
1952 return WINED3DERR_INVALIDCALL;
1955 This->NumberOfSwapChains = 1;
1956 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1957 if(!This->swapchains) {
1958 ERR("Out of memory!\n");
1959 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1960 return E_OUTOFMEMORY;
1962 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1964 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1965 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1966 This->render_targets[0] = swapchain->backBuffer[0];
1968 else {
1969 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1970 This->render_targets[0] = swapchain->frontBuffer;
1972 IWineD3DSurface_AddRef(This->render_targets[0]);
1973 /* Depth Stencil support */
1974 This->stencilBufferTarget = This->depthStencilBuffer;
1975 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1976 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1978 if (NULL != This->stencilBufferTarget) {
1979 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1982 /* Set up some starting GL setup */
1983 ENTER_GL();
1985 * Initialize openGL extension related variables
1986 * with Default values
1989 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
1990 /* Setup all the devices defaults */
1991 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1992 #if 0
1993 IWineD3DImpl_CheckGraphicsMemory();
1994 #endif
1995 LEAVE_GL();
1997 /* Initialize our list of GLSL programs */
1998 list_init(&This->glsl_shader_progs);
2000 { /* Set a default viewport */
2001 WINED3DVIEWPORT vp;
2002 vp.X = 0;
2003 vp.Y = 0;
2004 vp.Width = *(pPresentationParameters->BackBufferWidth);
2005 vp.Height = *(pPresentationParameters->BackBufferHeight);
2006 vp.MinZ = 0.0f;
2007 vp.MaxZ = 1.0f;
2008 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2011 /* Initialize the current view state */
2012 This->modelview_valid = 1;
2013 This->proj_valid = 0;
2014 This->view_ident = 1;
2015 This->last_was_rhw = 0;
2016 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2017 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2019 /* Clear the screen */
2020 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2022 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
2023 * This might create a problem in 2 situations:
2024 * ->The D3D default value is 0, but the opengl default value is something else
2025 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
2027 for(state = 0; state <= STATE_HIGHEST; state++) {
2028 IWineD3DDeviceImpl_MarkStateDirty(This, state);
2031 This->d3d_initialized = TRUE;
2032 return WINED3D_OK;
2035 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2037 int sampler;
2038 uint i;
2039 TRACE("(%p)\n", This);
2041 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2043 /* Delete the mouse cursor texture */
2044 if(This->cursorTexture) {
2045 ENTER_GL();
2046 glDeleteTextures(1, &This->cursorTexture);
2047 LEAVE_GL();
2048 This->cursorTexture = 0;
2051 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2052 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2055 /* Release the buffers (with sanity checks)*/
2056 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2057 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2058 if(This->depthStencilBuffer != This->stencilBufferTarget)
2059 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2061 This->stencilBufferTarget = NULL;
2063 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2064 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2065 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2067 TRACE("Setting rendertarget to NULL\n");
2068 This->render_targets[0] = NULL;
2070 if (This->depthStencilBuffer) {
2071 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2072 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2074 This->depthStencilBuffer = NULL;
2077 for(i=0; i < This->NumberOfSwapChains; i++) {
2078 TRACE("Releasing the implicit swapchain %d\n", i);
2079 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2080 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2084 HeapFree(GetProcessHeap(), 0, This->swapchains);
2085 This->swapchains = NULL;
2086 This->NumberOfSwapChains = 0;
2088 This->d3d_initialized = FALSE;
2089 return WINED3D_OK;
2092 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2094 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2096 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2097 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2098 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2099 * separately.
2101 This->ddraw_fullscreen = fullscreen;
2104 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2107 DEVMODEW DevModeW;
2108 int i;
2109 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2111 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2113 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2114 /* Ignore some modes if a description was passed */
2115 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2116 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2117 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2119 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2121 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2122 return D3D_OK;
2125 return D3D_OK;
2128 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2129 DEVMODEW devmode;
2130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2131 LONG ret;
2132 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2133 RECT clip_rc;
2135 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2137 /* Resize the screen even without a window:
2138 * The app could have unset it with SetCooperativeLevel, but not called
2139 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2140 * but we don't have any hwnd
2143 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2144 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2145 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2146 devmode.dmPelsWidth = pMode->Width;
2147 devmode.dmPelsHeight = pMode->Height;
2149 devmode.dmDisplayFrequency = pMode->RefreshRate;
2150 if (pMode->RefreshRate != 0) {
2151 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2154 /* Only change the mode if necessary */
2155 if( (This->ddraw_width == pMode->Width) &&
2156 (This->ddraw_height == pMode->Height) &&
2157 (This->ddraw_format == pMode->Format) &&
2158 (pMode->RefreshRate == 0) ) {
2159 return D3D_OK;
2162 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2163 if (ret != DISP_CHANGE_SUCCESSFUL) {
2164 if(devmode.dmDisplayFrequency != 0) {
2165 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2166 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2167 devmode.dmDisplayFrequency = 0;
2168 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2170 if(ret != DISP_CHANGE_SUCCESSFUL) {
2171 return DDERR_INVALIDMODE;
2175 /* Store the new values */
2176 This->ddraw_width = pMode->Width;
2177 This->ddraw_height = pMode->Height;
2178 This->ddraw_format = pMode->Format;
2180 /* Only do this with a window of course */
2181 if(This->ddraw_window)
2182 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2184 /* And finally clip mouse to our screen */
2185 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2186 ClipCursor(&clip_rc);
2188 return WINED3D_OK;
2191 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2193 *ppD3D= This->wineD3D;
2194 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2195 IWineD3D_AddRef(*ppD3D);
2196 return WINED3D_OK;
2199 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2200 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2201 * into the video ram as possible and seeing how many fit
2202 * you can also get the correct initial value from nvidia and ATI's driver via X
2203 * texture memory is video memory + AGP memory
2204 *******************/
2205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2206 static BOOL showfixmes = TRUE;
2207 if (showfixmes) {
2208 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2209 (wined3d_settings.emulated_textureram/(1024*1024)),
2210 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2211 showfixmes = FALSE;
2213 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2214 (wined3d_settings.emulated_textureram/(1024*1024)),
2215 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2216 /* return simulated texture memory left */
2217 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2222 /*****
2223 * Get / Set FVF
2224 *****/
2225 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2227 HRESULT hr = WINED3D_OK;
2229 /* Update the current state block */
2230 This->updateStateBlock->fvf = fvf;
2231 This->updateStateBlock->changed.fvf = TRUE;
2232 This->updateStateBlock->set.fvf = TRUE;
2234 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2235 return hr;
2239 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2242 *pfvf = This->stateBlock->fvf;
2243 return WINED3D_OK;
2246 /*****
2247 * Get / Set Stream Source
2248 *****/
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 IWineD3DVertexBuffer *oldSrc;
2253 /**TODO: instance and index data, see
2254 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2256 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2257 **************/
2259 /* D3d9 only, but shouldn't hurt d3d8 */
2260 UINT streamFlags;
2262 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2263 if (streamFlags) {
2264 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2265 FIXME("stream index data not supported\n");
2267 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2268 FIXME("stream instance data not supported\n");
2272 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2274 if (StreamNumber >= MAX_STREAMS) {
2275 WARN("Stream out of range %d\n", StreamNumber);
2276 return WINED3DERR_INVALIDCALL;
2279 oldSrc = This->stateBlock->streamSource[StreamNumber];
2280 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2282 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2283 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2284 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2285 if (pStreamData) {
2286 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2287 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2289 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2291 /* Handle recording of state blocks */
2292 if (This->isRecordingState) {
2293 TRACE("Recording... not performing anything\n");
2294 return WINED3D_OK;
2297 /* Same stream object: no action */
2298 if (oldSrc == pStreamData)
2299 return WINED3D_OK;
2301 /* Need to do a getParent and pass the reffs up */
2302 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2303 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2304 so for now, just count internally */
2305 if (pStreamData != NULL) {
2306 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2307 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2308 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2310 vbImpl->stream = StreamNumber;
2311 vbImpl->Flags |= VBFLAG_STREAM;
2312 IWineD3DVertexBuffer_AddRef(pStreamData);
2314 if (oldSrc != NULL) {
2315 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2316 IWineD3DVertexBuffer_Release(oldSrc);
2319 return WINED3D_OK;
2322 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2324 UINT streamFlags;
2326 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2327 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2330 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2331 if (streamFlags) {
2332 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2333 FIXME("stream index data not supported\n");
2335 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2336 FIXME("stream instance data not supported\n");
2340 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2342 if (StreamNumber >= MAX_STREAMS) {
2343 WARN("Stream out of range %d\n", StreamNumber);
2344 return WINED3DERR_INVALIDCALL;
2346 *pStream = This->stateBlock->streamSource[StreamNumber];
2347 *pStride = This->stateBlock->streamStride[StreamNumber];
2348 if (pOffset) {
2349 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2352 if (*pStream != NULL) {
2353 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2355 return WINED3D_OK;
2358 /*Should be quite easy, just an extension of vertexdata
2359 ref...
2360 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2362 The divider is a bit odd though
2364 VertexOffset = StartVertex / Divider * StreamStride +
2365 VertexIndex / Divider * StreamStride + StreamOffset
2368 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2371 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2372 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2374 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2375 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2376 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2378 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2379 FIXME("Stream indexing not fully supported\n");
2382 return WINED3D_OK;
2385 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2388 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2389 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2391 TRACE("(%p) : returning %d\n", This, *Divider);
2393 return WINED3D_OK;
2396 /*****
2397 * Get / Set & Multiply Transform
2398 *****/
2399 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2402 /* Most of this routine, comments included copied from ddraw tree initially: */
2403 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2405 /* Handle recording of state blocks */
2406 if (This->isRecordingState) {
2407 TRACE("Recording... not performing anything\n");
2408 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2409 This->updateStateBlock->set.transform[d3dts] = TRUE;
2410 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2411 return WINED3D_OK;
2415 * If the new matrix is the same as the current one,
2416 * we cut off any further processing. this seems to be a reasonable
2417 * optimization because as was noticed, some apps (warcraft3 for example)
2418 * tend towards setting the same matrix repeatedly for some reason.
2420 * From here on we assume that the new matrix is different, wherever it matters.
2422 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2423 TRACE("The app is setting the same matrix over again\n");
2424 return WINED3D_OK;
2425 } else {
2426 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2430 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2431 where ViewMat = Camera space, WorldMat = world space.
2433 In OpenGL, camera and world space is combined into GL_MODELVIEW
2434 matrix. The Projection matrix stay projection matrix.
2437 /* Capture the times we can just ignore the change for now */
2438 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2439 This->modelview_valid = FALSE;
2440 return WINED3D_OK;
2442 } else if (d3dts == WINED3DTS_PROJECTION) {
2443 This->proj_valid = FALSE;
2444 return WINED3D_OK;
2446 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2447 /* Indexed Vertex Blending Matrices 256 -> 511 */
2448 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2449 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2450 return WINED3D_OK;
2453 /* Now we really are going to have to change a matrix */
2454 ENTER_GL();
2456 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2457 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2458 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2459 unsigned int k;
2461 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2462 * NOTE: We have to reset the positions even if the light/plane is not currently
2463 * enabled, since the call to enable it will not reset the position.
2464 * NOTE2: Apparently texture transforms do NOT need reapplying
2467 PLIGHTINFOEL *lightChain = NULL;
2468 This->modelview_valid = FALSE;
2469 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2471 glMatrixMode(GL_MODELVIEW);
2472 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2473 glPushMatrix();
2474 glLoadMatrixf((const float *)lpmatrix);
2475 checkGLcall("glLoadMatrixf(...)");
2477 /* Reset lights */
2478 lightChain = This->stateBlock->lights;
2479 while (lightChain && lightChain->glIndex != -1) {
2480 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2481 checkGLcall("glLightfv posn");
2482 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2483 checkGLcall("glLightfv dirn");
2484 lightChain = lightChain->next;
2487 /* Reset Clipping Planes if clipping is enabled */
2488 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2489 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2490 checkGLcall("glClipPlane");
2492 glPopMatrix();
2494 } else { /* What was requested!?? */
2495 WARN("invalid matrix specified: %i\n", d3dts);
2498 /* Release lock, all done */
2499 LEAVE_GL();
2500 return WINED3D_OK;
2503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2506 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2507 return WINED3D_OK;
2510 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2511 WINED3DMATRIX *mat = NULL;
2512 WINED3DMATRIX temp;
2514 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2515 * below means it will be recorded in a state block change, but it
2516 * works regardless where it is recorded.
2517 * If this is found to be wrong, change to StateBlock.
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2520 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2522 if (State < HIGHEST_TRANSFORMSTATE)
2524 mat = &This->updateStateBlock->transforms[State];
2525 } else {
2526 FIXME("Unhandled transform state!!\n");
2529 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2531 /* Apply change via set transform - will reapply to eg. lights this way */
2532 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2535 /*****
2536 * Get / Set Light
2537 *****/
2538 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2539 you can reference any indexes you want as long as that number max are enabled at any
2540 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2541 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2542 but when recording, just build a chain pretty much of commands to be replayed. */
2544 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2545 float rho;
2546 PLIGHTINFOEL *object, *temp;
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2551 /* If recording state block, just add to end of lights chain */
2552 if (This->isRecordingState) {
2553 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2554 if (NULL == object) {
2555 return WINED3DERR_OUTOFVIDEOMEMORY;
2557 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2558 object->OriginalIndex = Index;
2559 object->glIndex = -1;
2560 object->changed = TRUE;
2562 /* Add to the END of the chain of lights changes to be replayed */
2563 if (This->updateStateBlock->lights == NULL) {
2564 This->updateStateBlock->lights = object;
2565 } else {
2566 temp = This->updateStateBlock->lights;
2567 while (temp->next != NULL) temp=temp->next;
2568 temp->next = object;
2570 TRACE("Recording... not performing anything more\n");
2571 return WINED3D_OK;
2574 /* Ok, not recording any longer so do real work */
2575 object = This->stateBlock->lights;
2576 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2578 /* If we didn't find it in the list of lights, time to add it */
2579 if (object == NULL) {
2580 PLIGHTINFOEL *insertAt,*prevPos;
2582 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2583 if (NULL == object) {
2584 return WINED3DERR_OUTOFVIDEOMEMORY;
2586 object->OriginalIndex = Index;
2587 object->glIndex = -1;
2589 /* Add it to the front of list with the idea that lights will be changed as needed
2590 BUT after any lights currently assigned GL indexes */
2591 insertAt = This->stateBlock->lights;
2592 prevPos = NULL;
2593 while (insertAt != NULL && insertAt->glIndex != -1) {
2594 prevPos = insertAt;
2595 insertAt = insertAt->next;
2598 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2599 This->stateBlock->lights = object;
2600 } else if (insertAt == NULL) { /* End of list */
2601 prevPos->next = object;
2602 object->prev = prevPos;
2603 } else { /* Middle of chain */
2604 if (prevPos == NULL) {
2605 This->stateBlock->lights = object;
2606 } else {
2607 prevPos->next = object;
2609 object->prev = prevPos;
2610 object->next = insertAt;
2611 insertAt->prev = object;
2615 /* Initialize the object */
2616 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,
2617 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2618 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2619 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2620 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2621 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2622 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2624 /* Save away the information */
2625 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2627 switch (pLight->Type) {
2628 case WINED3DLIGHT_POINT:
2629 /* Position */
2630 object->lightPosn[0] = pLight->Position.x;
2631 object->lightPosn[1] = pLight->Position.y;
2632 object->lightPosn[2] = pLight->Position.z;
2633 object->lightPosn[3] = 1.0f;
2634 object->cutoff = 180.0f;
2635 /* FIXME: Range */
2636 break;
2638 case WINED3DLIGHT_DIRECTIONAL:
2639 /* Direction */
2640 object->lightPosn[0] = -pLight->Direction.x;
2641 object->lightPosn[1] = -pLight->Direction.y;
2642 object->lightPosn[2] = -pLight->Direction.z;
2643 object->lightPosn[3] = 0.0;
2644 object->exponent = 0.0f;
2645 object->cutoff = 180.0f;
2646 break;
2648 case WINED3DLIGHT_SPOT:
2649 /* Position */
2650 object->lightPosn[0] = pLight->Position.x;
2651 object->lightPosn[1] = pLight->Position.y;
2652 object->lightPosn[2] = pLight->Position.z;
2653 object->lightPosn[3] = 1.0;
2655 /* Direction */
2656 object->lightDirn[0] = pLight->Direction.x;
2657 object->lightDirn[1] = pLight->Direction.y;
2658 object->lightDirn[2] = pLight->Direction.z;
2659 object->lightDirn[3] = 1.0;
2662 * opengl-ish and d3d-ish spot lights use too different models for the
2663 * light "intensity" as a function of the angle towards the main light direction,
2664 * so we only can approximate very roughly.
2665 * however spot lights are rather rarely used in games (if ever used at all).
2666 * furthermore if still used, probably nobody pays attention to such details.
2668 if (pLight->Falloff == 0) {
2669 rho = 6.28f;
2670 } else {
2671 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2673 if (rho < 0.0001) rho = 0.0001f;
2674 object->exponent = -0.3/log(cos(rho/2));
2675 if (object->exponent > 128.0) {
2676 object->exponent = 128.0;
2678 object->cutoff = pLight->Phi*90/M_PI;
2680 /* FIXME: Range */
2681 break;
2683 default:
2684 FIXME("Unrecognized light type %d\n", pLight->Type);
2687 /* Update the live definitions if the light is currently assigned a glIndex */
2688 if (object->glIndex != -1) {
2689 setup_light(iface, object->glIndex, object);
2691 return WINED3D_OK;
2694 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2695 PLIGHTINFOEL *lightInfo = NULL;
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2699 /* Locate the light in the live lights */
2700 lightInfo = This->stateBlock->lights;
2701 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2703 if (lightInfo == NULL) {
2704 TRACE("Light information requested but light not defined\n");
2705 return WINED3DERR_INVALIDCALL;
2708 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2709 return WINED3D_OK;
2712 /*****
2713 * Get / Set Light Enable
2714 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2715 *****/
2716 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2717 PLIGHTINFOEL *lightInfo = NULL;
2718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2719 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2721 /* Tests show true = 128...not clear why */
2723 Enable = Enable? 128: 0;
2725 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2726 if (This->isRecordingState) {
2727 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2728 if (NULL == lightInfo) {
2729 return WINED3DERR_OUTOFVIDEOMEMORY;
2731 lightInfo->OriginalIndex = Index;
2732 lightInfo->glIndex = -1;
2733 lightInfo->enabledChanged = TRUE;
2734 lightInfo->lightEnabled = Enable;
2736 /* Add to the END of the chain of lights changes to be replayed */
2737 if (This->updateStateBlock->lights == NULL) {
2738 This->updateStateBlock->lights = lightInfo;
2739 } else {
2740 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2741 while (temp->next != NULL) temp=temp->next;
2742 temp->next = lightInfo;
2744 TRACE("Recording... not performing anything more\n");
2745 return WINED3D_OK;
2748 /* Not recording... So, locate the light in the live lights */
2749 lightInfo = This->stateBlock->lights;
2750 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2752 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2753 if (lightInfo == NULL) {
2755 TRACE("Light enabled requested but light not defined, so defining one!\n");
2756 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2758 /* Search for it again! Should be fairly quick as near head of list */
2759 lightInfo = This->stateBlock->lights;
2760 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2761 if (lightInfo == NULL) {
2762 FIXME("Adding default lights has failed dismally\n");
2763 return WINED3DERR_INVALIDCALL;
2767 /* OK, we now have a light... */
2768 if (!Enable) {
2770 /* If we are disabling it, check it was enabled, and
2771 still only do something if it has assigned a glIndex (which it should have!) */
2772 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2773 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2774 ENTER_GL();
2775 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2776 checkGLcall("glDisable GL_LIGHT0+Index");
2777 LEAVE_GL();
2778 } else {
2779 TRACE("Nothing to do as light was not enabled\n");
2781 lightInfo->lightEnabled = Enable;
2782 } else {
2784 /* We are enabling it. If it is enabled, it's really simple */
2785 if (lightInfo->lightEnabled) {
2786 /* nop */
2787 TRACE("Nothing to do as light was enabled\n");
2789 /* If it already has a glIndex, it's still simple */
2790 } else if (lightInfo->glIndex != -1) {
2791 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2792 lightInfo->lightEnabled = Enable;
2793 ENTER_GL();
2794 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2795 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2796 LEAVE_GL();
2798 /* Otherwise got to find space - lights are ordered gl indexes first */
2799 } else {
2800 PLIGHTINFOEL *bsf = NULL;
2801 PLIGHTINFOEL *pos = This->stateBlock->lights;
2802 PLIGHTINFOEL *prev = NULL;
2803 int Index= 0;
2804 int glIndex = -1;
2806 /* Try to minimize changes as much as possible */
2807 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2809 /* Try to remember which index can be replaced if necessary */
2810 if (bsf==NULL && !pos->lightEnabled) {
2811 /* Found a light we can replace, save as best replacement */
2812 bsf = pos;
2815 /* Step to next space */
2816 prev = pos;
2817 pos = pos->next;
2818 Index ++;
2821 /* If we have too many active lights, fail the call */
2822 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2823 FIXME("Program requests too many concurrent lights\n");
2824 return WINED3DERR_INVALIDCALL;
2826 /* If we have allocated all lights, but not all are enabled,
2827 reuse one which is not enabled */
2828 } else if (Index == This->maxConcurrentLights) {
2829 /* use bsf - Simply swap the new light and the BSF one */
2830 PLIGHTINFOEL *bsfNext = bsf->next;
2831 PLIGHTINFOEL *bsfPrev = bsf->prev;
2833 /* Sort out ends */
2834 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2835 if (bsf->prev != NULL) {
2836 bsf->prev->next = lightInfo;
2837 } else {
2838 This->stateBlock->lights = lightInfo;
2841 /* If not side by side, lots of chains to update */
2842 if (bsf->next != lightInfo) {
2843 lightInfo->prev->next = bsf;
2844 bsf->next->prev = lightInfo;
2845 bsf->next = lightInfo->next;
2846 bsf->prev = lightInfo->prev;
2847 lightInfo->next = bsfNext;
2848 lightInfo->prev = bsfPrev;
2850 } else {
2851 /* Simple swaps */
2852 bsf->prev = lightInfo;
2853 bsf->next = lightInfo->next;
2854 lightInfo->next = bsf;
2855 lightInfo->prev = bsfPrev;
2859 /* Update states */
2860 glIndex = bsf->glIndex;
2861 bsf->glIndex = -1;
2862 lightInfo->glIndex = glIndex;
2863 lightInfo->lightEnabled = Enable;
2865 /* Finally set up the light in gl itself */
2866 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2867 ENTER_GL();
2868 setup_light(iface, glIndex, lightInfo);
2869 glEnable(GL_LIGHT0 + glIndex);
2870 checkGLcall("glEnable GL_LIGHT0 new setup");
2871 LEAVE_GL();
2873 /* If we reached the end of the allocated lights, with space in the
2874 gl lights, setup a new light */
2875 } else if (pos->glIndex == -1) {
2877 /* We reached the end of the allocated gl lights, so already
2878 know the index of the next one! */
2879 glIndex = Index;
2880 lightInfo->glIndex = glIndex;
2881 lightInfo->lightEnabled = Enable;
2883 /* In an ideal world, it's already in the right place */
2884 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2885 /* No need to move it */
2886 } else {
2887 /* Remove this light from the list */
2888 lightInfo->prev->next = lightInfo->next;
2889 if (lightInfo->next != NULL) {
2890 lightInfo->next->prev = lightInfo->prev;
2893 /* Add in at appropriate place (inbetween prev and pos) */
2894 lightInfo->prev = prev;
2895 lightInfo->next = pos;
2896 if (prev == NULL) {
2897 This->stateBlock->lights = lightInfo;
2898 } else {
2899 prev->next = lightInfo;
2901 if (pos != NULL) {
2902 pos->prev = lightInfo;
2906 /* Finally set up the light in gl itself */
2907 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2908 ENTER_GL();
2909 setup_light(iface, glIndex, lightInfo);
2910 glEnable(GL_LIGHT0 + glIndex);
2911 checkGLcall("glEnable GL_LIGHT0 new setup");
2912 LEAVE_GL();
2917 return WINED3D_OK;
2920 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2922 PLIGHTINFOEL *lightInfo = NULL;
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 TRACE("(%p) : for idx(%d)\n", This, Index);
2926 /* Locate the light in the live lights */
2927 lightInfo = This->stateBlock->lights;
2928 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2930 if (lightInfo == NULL) {
2931 TRACE("Light enabled state requested but light not defined\n");
2932 return WINED3DERR_INVALIDCALL;
2934 *pEnable = lightInfo->lightEnabled;
2935 return WINED3D_OK;
2938 /*****
2939 * Get / Set Clip Planes
2940 *****/
2941 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2945 /* Validate Index */
2946 if (Index >= GL_LIMITS(clipplanes)) {
2947 TRACE("Application has requested clipplane this device doesn't support\n");
2948 return WINED3DERR_INVALIDCALL;
2951 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2952 This->updateStateBlock->set.clipplane[Index] = TRUE;
2953 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2954 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2955 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2956 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2958 /* Handle recording of state blocks */
2959 if (This->isRecordingState) {
2960 TRACE("Recording... not performing anything\n");
2961 return WINED3D_OK;
2964 /* Apply it */
2966 ENTER_GL();
2968 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2969 glMatrixMode(GL_MODELVIEW);
2970 glPushMatrix();
2971 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2973 TRACE("Clipplane [%f,%f,%f,%f]\n",
2974 This->updateStateBlock->clipplane[Index][0],
2975 This->updateStateBlock->clipplane[Index][1],
2976 This->updateStateBlock->clipplane[Index][2],
2977 This->updateStateBlock->clipplane[Index][3]);
2978 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2979 checkGLcall("glClipPlane");
2981 glPopMatrix();
2982 LEAVE_GL();
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 TRACE("(%p) : for idx %d\n", This, Index);
2991 /* Validate Index */
2992 if (Index >= GL_LIMITS(clipplanes)) {
2993 TRACE("Application has requested clipplane this device doesn't support\n");
2994 return WINED3DERR_INVALIDCALL;
2997 pPlane[0] = This->stateBlock->clipplane[Index][0];
2998 pPlane[1] = This->stateBlock->clipplane[Index][1];
2999 pPlane[2] = This->stateBlock->clipplane[Index][2];
3000 pPlane[3] = This->stateBlock->clipplane[Index][3];
3001 return WINED3D_OK;
3004 /*****
3005 * Get / Set Clip Plane Status
3006 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3007 *****/
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 FIXME("(%p) : stub\n", This);
3011 if (NULL == pClipStatus) {
3012 return WINED3DERR_INVALIDCALL;
3014 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3015 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3016 return WINED3D_OK;
3019 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 FIXME("(%p) : stub\n", This);
3022 if (NULL == pClipStatus) {
3023 return WINED3DERR_INVALIDCALL;
3025 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3026 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3027 return WINED3D_OK;
3030 /*****
3031 * Get / Set Material
3032 *****/
3033 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 This->updateStateBlock->changed.material = TRUE;
3037 This->updateStateBlock->set.material = TRUE;
3038 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3040 /* Handle recording of state blocks */
3041 if (This->isRecordingState) {
3042 TRACE("Recording... not performing anything\n");
3043 return WINED3D_OK;
3046 ENTER_GL();
3047 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3048 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3049 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3050 pMaterial->Ambient.b, pMaterial->Ambient.a);
3051 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3052 pMaterial->Specular.b, pMaterial->Specular.a);
3053 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3054 pMaterial->Emissive.b, pMaterial->Emissive.a);
3055 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3057 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3058 checkGLcall("glMaterialfv(GL_AMBIENT)");
3059 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3060 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3062 /* Only change material color if specular is enabled, otherwise it is set to black */
3063 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3064 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3065 checkGLcall("glMaterialfv(GL_SPECULAR");
3066 } else {
3067 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3068 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3069 checkGLcall("glMaterialfv(GL_SPECULAR");
3071 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3072 checkGLcall("glMaterialfv(GL_EMISSION)");
3073 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3074 checkGLcall("glMaterialf(GL_SHININESS");
3076 LEAVE_GL();
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3083 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3084 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3085 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3086 pMaterial->Ambient.b, pMaterial->Ambient.a);
3087 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3088 pMaterial->Specular.b, pMaterial->Specular.a);
3089 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3090 pMaterial->Emissive.b, pMaterial->Emissive.a);
3091 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3093 return WINED3D_OK;
3096 /*****
3097 * Get / Set Indices
3098 *****/
3099 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3100 UINT BaseVertexIndex) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 IWineD3DIndexBuffer *oldIdxs;
3104 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3105 oldIdxs = This->updateStateBlock->pIndexData;
3107 This->updateStateBlock->changed.indices = TRUE;
3108 This->updateStateBlock->set.indices = TRUE;
3109 This->updateStateBlock->pIndexData = pIndexData;
3110 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3112 /* Handle recording of state blocks */
3113 if (This->isRecordingState) {
3114 TRACE("Recording... not performing anything\n");
3115 return WINED3D_OK;
3118 if (NULL != pIndexData) {
3119 IWineD3DIndexBuffer_AddRef(pIndexData);
3121 if (NULL != oldIdxs) {
3122 IWineD3DIndexBuffer_Release(oldIdxs);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 *ppIndexData = This->stateBlock->pIndexData;
3132 /* up ref count on ppindexdata */
3133 if (*ppIndexData) {
3134 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3135 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3136 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3137 }else{
3138 TRACE("(%p) No index data set\n", This);
3140 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3142 return WINED3D_OK;
3145 /*****
3146 * Get / Set Viewports
3147 *****/
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 TRACE("(%p)\n", This);
3152 This->updateStateBlock->changed.viewport = TRUE;
3153 This->updateStateBlock->set.viewport = TRUE;
3154 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3156 /* Handle recording of state blocks */
3157 if (This->isRecordingState) {
3158 TRACE("Recording... not performing anything\n");
3159 return WINED3D_OK;
3161 This->viewport_changed = TRUE;
3163 ENTER_GL();
3165 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3166 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3168 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3169 checkGLcall("glDepthRange");
3170 /* Note: GL requires lower left, DirectX supplies upper left */
3171 /* TODO: replace usage of renderTarget with context management */
3172 glViewport(pViewport->X,
3173 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3174 pViewport->Width, pViewport->Height);
3176 checkGLcall("glViewport");
3178 LEAVE_GL();
3180 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 TRACE("(%p)\n", This);
3187 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3188 return WINED3D_OK;
3191 /*****
3192 * Get / Set Render States
3193 * TODO: Verify against dx9 definitions
3194 *****/
3195 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 DWORD oldValue = This->stateBlock->renderState[State];
3200 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3202 This->updateStateBlock->changed.renderState[State] = TRUE;
3203 This->updateStateBlock->set.renderState[State] = TRUE;
3204 This->updateStateBlock->renderState[State] = Value;
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3209 return WINED3D_OK;
3212 /* Compared here and not before the assignment to allow proper stateblock recording */
3213 if(Value == oldValue) {
3214 TRACE("Application is setting the old value over, nothing to do\n");
3215 } else {
3216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3219 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3225 *pValue = This->stateBlock->renderState[State];
3226 return WINED3D_OK;
3229 /*****
3230 * Get / Set Sampler States
3231 * TODO: Verify against dx9 definitions
3232 *****/
3234 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3239 * SetSampler is designed to allow for more than the standard up to 8 textures
3240 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3241 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3243 * http://developer.nvidia.com/object/General_FAQ.html#t6
3245 * There are two new settings for GForce
3246 * the sampler one:
3247 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3248 * and the texture one:
3249 * GL_MAX_TEXTURE_COORDS_ARB.
3250 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3251 ******************/
3252 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3253 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3254 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3255 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3256 return WINED3DERR_INVALIDCALL;
3259 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3260 debug_d3dsamplerstate(Type), Type, Value);
3261 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3262 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3263 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3265 /* Handle recording of state blocks */
3266 if (This->isRecordingState) {
3267 TRACE("Recording... not performing anything\n");
3268 return WINED3D_OK;
3271 if(oldValue == Value) {
3272 TRACE("Application is setting the old value over, nothing to do\n");
3273 return WINED3D_OK;
3276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3278 return WINED3D_OK;
3281 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 /** TODO: check that sampler is in range **/
3284 *Value = This->stateBlock->samplerState[Sampler][Type];
3285 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3287 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 RECT windowRect;
3293 UINT winHeight;
3295 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3296 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3297 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3299 winHeight = windowRect.bottom - windowRect.top;
3300 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3301 pRect->right - pRect->left, pRect->bottom - pRect->top);
3302 ENTER_GL();
3303 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3304 checkGLcall("glScissor");
3305 LEAVE_GL();
3307 return WINED3D_OK;
3310 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3312 GLint scissorBox[4];
3314 ENTER_GL();
3315 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3316 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3317 pRect->left = scissorBox[0];
3318 pRect->top = scissorBox[1];
3319 pRect->right = scissorBox[0] + scissorBox[2];
3320 pRect->bottom = scissorBox[1] + scissorBox[3];
3321 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3322 LEAVE_GL();
3323 return WINED3D_OK;
3326 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3328 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3330 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3332 This->updateStateBlock->vertexDecl = pDecl;
3333 This->updateStateBlock->changed.vertexDecl = TRUE;
3334 This->updateStateBlock->set.vertexDecl = TRUE;
3336 if (This->isRecordingState) {
3337 TRACE("Recording... not performing anything\n");
3340 if (NULL != pDecl) {
3341 IWineD3DVertexDeclaration_AddRef(pDecl);
3343 if (NULL != oldDecl) {
3344 IWineD3DVertexDeclaration_Release(oldDecl);
3346 return WINED3D_OK;
3349 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3354 *ppDecl = This->stateBlock->vertexDecl;
3355 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3356 return WINED3D_OK;
3359 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3361 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3363 This->updateStateBlock->vertexShader = pShader;
3364 This->updateStateBlock->changed.vertexShader = TRUE;
3365 This->updateStateBlock->set.vertexShader = TRUE;
3367 if (This->isRecordingState) {
3368 TRACE("Recording... not performing anything\n");
3371 if (NULL != pShader) {
3372 IWineD3DVertexShader_AddRef(pShader);
3374 if (NULL != oldShader) {
3375 IWineD3DVertexShader_Release(oldShader);
3378 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3380 * TODO: merge HAL shaders context switching from prototype
3382 return WINED3D_OK;
3385 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3388 if (NULL == ppShader) {
3389 return WINED3DERR_INVALIDCALL;
3391 *ppShader = This->stateBlock->vertexShader;
3392 if( NULL != *ppShader)
3393 IWineD3DVertexShader_AddRef(*ppShader);
3395 TRACE("(%p) : returning %p\n", This, *ppShader);
3396 return WINED3D_OK;
3399 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3400 IWineD3DDevice *iface,
3401 UINT start,
3402 CONST BOOL *srcData,
3403 UINT count) {
3405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3406 int i, cnt = min(count, MAX_CONST_B - start);
3408 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3409 iface, srcData, start, count);
3411 if (srcData == NULL || cnt < 0)
3412 return WINED3DERR_INVALIDCALL;
3414 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3415 for (i = 0; i < cnt; i++)
3416 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3418 for (i = start; i < cnt + start; ++i) {
3419 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3420 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 BOOL *dstData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int cnt = min(count, MAX_CONST_B - start);
3435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3436 iface, dstData, start, count);
3438 if (dstData == NULL || cnt < 0)
3439 return WINED3DERR_INVALIDCALL;
3441 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3442 return WINED3D_OK;
3445 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3446 IWineD3DDevice *iface,
3447 UINT start,
3448 CONST int *srcData,
3449 UINT count) {
3451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3452 int i, cnt = min(count, MAX_CONST_I - start);
3454 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3455 iface, srcData, start, count);
3457 if (srcData == NULL || cnt < 0)
3458 return WINED3DERR_INVALIDCALL;
3460 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3461 for (i = 0; i < cnt; i++)
3462 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3463 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3465 for (i = start; i < cnt + start; ++i) {
3466 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3467 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3470 return WINED3D_OK;
3473 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3474 IWineD3DDevice *iface,
3475 UINT start,
3476 int *dstData,
3477 UINT count) {
3479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 int cnt = min(count, MAX_CONST_I - start);
3482 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3483 iface, dstData, start, count);
3485 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3486 return WINED3DERR_INVALIDCALL;
3488 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3489 return WINED3D_OK;
3492 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3493 IWineD3DDevice *iface,
3494 UINT start,
3495 CONST float *srcData,
3496 UINT count) {
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3501 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3502 iface, srcData, start, count);
3504 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3505 return WINED3DERR_INVALIDCALL;
3507 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3508 for (i = 0; i < cnt; i++)
3509 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3510 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3512 for (i = start; i < cnt + start; ++i) {
3513 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3514 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3515 ptr->idx = i;
3516 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3517 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3519 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3522 return WINED3D_OK;
3525 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3526 IWineD3DDevice *iface,
3527 UINT start,
3528 float *dstData,
3529 UINT count) {
3531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3532 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3534 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3535 iface, dstData, start, count);
3537 if (dstData == NULL || cnt < 0)
3538 return WINED3DERR_INVALIDCALL;
3540 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3541 return WINED3D_OK;
3544 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3545 DWORD i;
3546 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3551 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3552 DWORD i, tex;
3553 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3554 * it is never called.
3556 * Rules are:
3557 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3558 * that would be really messy and require shader recompilation
3559 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3560 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3561 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3562 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3564 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3565 if(This->oneToOneTexUnitMap) {
3566 TRACE("Not touching 1:1 map\n");
3567 return;
3569 TRACE("Restoring 1:1 texture unit mapping\n");
3570 /* Restore a 1:1 mapping */
3571 for(i = 0; i < MAX_SAMPLERS; i++) {
3572 if(This->texUnitMap[i] != i) {
3573 This->texUnitMap[i] = i;
3574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3575 markTextureStagesDirty(This, i);
3578 This->oneToOneTexUnitMap = TRUE;
3579 return;
3580 } else {
3581 /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
3582 * First, see if we can succeed at all
3584 tex = 0;
3585 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3586 if(This->stateBlock->textures[i] == NULL) tex++;
3589 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3590 FIXME("Too many bound textures to support the combiner settings\n");
3591 return;
3594 /* Now work out the mapping */
3595 tex = 0;
3596 This->oneToOneTexUnitMap = FALSE;
3597 WARN("Non 1:1 mapping UNTESTED!\n");
3598 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3599 /* Skip NULL textures */
3600 if (!This->stateBlock->textures[i]) {
3601 /* Map to -1, so the check below doesn't fail if a non-NULL
3602 * texture is set on this stage */
3603 TRACE("Mapping texture stage %d to -1\n", i);
3604 This->texUnitMap[i] = -1;
3606 continue;
3609 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3610 if(This->texUnitMap[i] != tex) {
3611 This->texUnitMap[i] = tex;
3612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3613 markTextureStagesDirty(This, i);
3616 ++tex;
3621 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3623 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3624 This->updateStateBlock->pixelShader = pShader;
3625 This->updateStateBlock->changed.pixelShader = TRUE;
3626 This->updateStateBlock->set.pixelShader = TRUE;
3628 /* Handle recording of state blocks */
3629 if (This->isRecordingState) {
3630 TRACE("Recording... not performing anything\n");
3633 if (NULL != pShader) {
3634 IWineD3DPixelShader_AddRef(pShader);
3636 if (NULL != oldShader) {
3637 IWineD3DPixelShader_Release(oldShader);
3640 if (This->isRecordingState) {
3641 TRACE("Recording... not performing anything\n");
3642 return WINED3D_OK;
3645 if(pShader == oldShader) {
3646 TRACE("App is setting the old pixel shader over, nothing to do\n");
3647 return WINED3D_OK;
3650 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3653 /* Rebuild the texture unit mapping if nvrc's are supported */
3654 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3655 IWineD3DDeviceImpl_FindTexUnitMap(This);
3658 return WINED3D_OK;
3661 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3664 if (NULL == ppShader) {
3665 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3666 return WINED3DERR_INVALIDCALL;
3669 *ppShader = This->stateBlock->pixelShader;
3670 if (NULL != *ppShader) {
3671 IWineD3DPixelShader_AddRef(*ppShader);
3673 TRACE("(%p) : returning %p\n", This, *ppShader);
3674 return WINED3D_OK;
3677 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3678 IWineD3DDevice *iface,
3679 UINT start,
3680 CONST BOOL *srcData,
3681 UINT count) {
3683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3684 int i, cnt = min(count, MAX_CONST_B - start);
3686 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3687 iface, srcData, start, count);
3689 if (srcData == NULL || cnt < 0)
3690 return WINED3DERR_INVALIDCALL;
3692 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3693 for (i = 0; i < cnt; i++)
3694 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3696 for (i = start; i < cnt + start; ++i) {
3697 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3698 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3701 return WINED3D_OK;
3704 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3705 IWineD3DDevice *iface,
3706 UINT start,
3707 BOOL *dstData,
3708 UINT count) {
3710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3711 int cnt = min(count, MAX_CONST_B - start);
3713 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3714 iface, dstData, start, count);
3716 if (dstData == NULL || cnt < 0)
3717 return WINED3DERR_INVALIDCALL;
3719 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3720 return WINED3D_OK;
3723 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3724 IWineD3DDevice *iface,
3725 UINT start,
3726 CONST int *srcData,
3727 UINT count) {
3729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3730 int i, cnt = min(count, MAX_CONST_I - start);
3732 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3733 iface, srcData, start, count);
3735 if (srcData == NULL || cnt < 0)
3736 return WINED3DERR_INVALIDCALL;
3738 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3739 for (i = 0; i < cnt; i++)
3740 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3741 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3743 for (i = start; i < cnt + start; ++i) {
3744 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3745 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3748 return WINED3D_OK;
3751 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3752 IWineD3DDevice *iface,
3753 UINT start,
3754 int *dstData,
3755 UINT count) {
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 int cnt = min(count, MAX_CONST_I - start);
3760 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3761 iface, dstData, start, count);
3763 if (dstData == NULL || cnt < 0)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3767 return WINED3D_OK;
3770 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3771 IWineD3DDevice *iface,
3772 UINT start,
3773 CONST float *srcData,
3774 UINT count) {
3776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3777 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3779 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3780 iface, srcData, start, count);
3782 if (srcData == NULL || cnt < 0)
3783 return WINED3DERR_INVALIDCALL;
3785 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3786 for (i = 0; i < cnt; i++)
3787 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3788 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3790 for (i = start; i < cnt + start; ++i) {
3791 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3792 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3793 ptr->idx = i;
3794 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3795 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3797 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3800 return WINED3D_OK;
3803 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3804 IWineD3DDevice *iface,
3805 UINT start,
3806 float *dstData,
3807 UINT count) {
3809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3810 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3812 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3813 iface, dstData, start, count);
3815 if (dstData == NULL || cnt < 0)
3816 return WINED3DERR_INVALIDCALL;
3818 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3819 return WINED3D_OK;
3822 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3823 static HRESULT
3824 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3825 char *dest_ptr, *dest_conv = NULL;
3826 unsigned int i;
3827 DWORD DestFVF = dest->fvf;
3828 WINED3DVIEWPORT vp;
3829 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3830 BOOL doClip;
3831 int numTextures;
3833 if (SrcFVF & WINED3DFVF_NORMAL) {
3834 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3837 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3838 ERR("Source has no position mask\n");
3839 return WINED3DERR_INVALIDCALL;
3842 /* We might access VBOs from this code, so hold the lock */
3843 ENTER_GL();
3845 if (dest->resource.allocatedMemory == NULL) {
3846 /* This may happen if we do direct locking into a vbo. Unlikely,
3847 * but theoretically possible(ddraw processvertices test)
3849 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3850 if(!dest->resource.allocatedMemory) {
3851 LEAVE_GL();
3852 ERR("Out of memory\n");
3853 return E_OUTOFMEMORY;
3855 if(dest->vbo) {
3856 void *src;
3857 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3858 checkGLcall("glBindBufferARB");
3859 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3860 if(src) {
3861 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3863 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3864 checkGLcall("glUnmapBufferARB");
3868 /* Get a pointer into the destination vbo(create one if none exists) and
3869 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3871 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3872 CreateVBO(dest);
3875 if(dest->vbo) {
3876 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3877 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3878 if(!dest_conv) {
3879 ERR("glMapBuffer failed\n");
3880 /* Continue without storing converted vertices */
3884 /* Should I clip?
3885 * a) WINED3DRS_CLIPPING is enabled
3886 * b) WINED3DVOP_CLIP is passed
3888 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3889 static BOOL warned = FALSE;
3891 * The clipping code is not quite correct. Some things need
3892 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3893 * so disable clipping for now.
3894 * (The graphics in Half-Life are broken, and my processvertices
3895 * test crashes with IDirect3DDevice3)
3896 doClip = TRUE;
3898 doClip = FALSE;
3899 if(!warned) {
3900 warned = TRUE;
3901 FIXME("Clipping is broken and disabled for now\n");
3903 } else doClip = FALSE;
3904 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3905 if(dest_conv) {
3906 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3909 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3910 WINED3DTS_VIEW,
3911 &view_mat);
3912 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3913 WINED3DTS_PROJECTION,
3914 &proj_mat);
3915 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3916 WINED3DTS_WORLDMATRIX(0),
3917 &world_mat);
3919 TRACE("View mat:\n");
3920 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); \
3921 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); \
3922 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); \
3923 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); \
3925 TRACE("Proj mat:\n");
3926 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); \
3927 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); \
3928 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); \
3929 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); \
3931 TRACE("World mat:\n");
3932 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); \
3933 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); \
3934 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); \
3935 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); \
3937 /* Get the viewport */
3938 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3939 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3940 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3942 multiply_matrix(&mat,&view_mat,&world_mat);
3943 multiply_matrix(&mat,&proj_mat,&mat);
3945 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3947 for (i = 0; i < dwCount; i+= 1) {
3948 unsigned int tex_index;
3950 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3951 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3952 /* The position first */
3953 float *p =
3954 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3955 float x, y, z, rhw;
3956 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3958 /* Multiplication with world, view and projection matrix */
3959 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);
3960 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);
3961 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);
3962 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);
3964 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3966 /* WARNING: The following things are taken from d3d7 and were not yet checked
3967 * against d3d8 or d3d9!
3970 /* Clipping conditions: From
3971 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3973 * A vertex is clipped if it does not match the following requirements
3974 * -rhw < x <= rhw
3975 * -rhw < y <= rhw
3976 * 0 < z <= rhw
3977 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3979 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3980 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3984 if( !doClip ||
3985 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3986 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3987 ( rhw > eps ) ) ) {
3989 /* "Normal" viewport transformation (not clipped)
3990 * 1) The values are divided by rhw
3991 * 2) The y axis is negative, so multiply it with -1
3992 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3993 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3994 * 4) Multiply x with Width/2 and add Width/2
3995 * 5) The same for the height
3996 * 6) Add the viewpoint X and Y to the 2D coordinates and
3997 * The minimum Z value to z
3998 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4000 * Well, basically it's simply a linear transformation into viewport
4001 * coordinates
4004 x /= rhw;
4005 y /= rhw;
4006 z /= rhw;
4008 y *= -1;
4010 x *= vp.Width / 2;
4011 y *= vp.Height / 2;
4012 z *= vp.MaxZ - vp.MinZ;
4014 x += vp.Width / 2 + vp.X;
4015 y += vp.Height / 2 + vp.Y;
4016 z += vp.MinZ;
4018 rhw = 1 / rhw;
4019 } else {
4020 /* That vertex got clipped
4021 * Contrary to OpenGL it is not dropped completely, it just
4022 * undergoes a different calculation.
4024 TRACE("Vertex got clipped\n");
4025 x += rhw;
4026 y += rhw;
4028 x /= 2;
4029 y /= 2;
4031 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4032 * outside of the main vertex buffer memory. That needs some more
4033 * investigation...
4037 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4040 ( (float *) dest_ptr)[0] = x;
4041 ( (float *) dest_ptr)[1] = y;
4042 ( (float *) dest_ptr)[2] = z;
4043 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4045 dest_ptr += 3 * sizeof(float);
4047 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4048 dest_ptr += sizeof(float);
4051 if(dest_conv) {
4052 float w = 1 / rhw;
4053 ( (float *) dest_conv)[0] = x * w;
4054 ( (float *) dest_conv)[1] = y * w;
4055 ( (float *) dest_conv)[2] = z * w;
4056 ( (float *) dest_conv)[3] = w;
4058 dest_conv += 3 * sizeof(float);
4060 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4061 dest_conv += sizeof(float);
4065 if (DestFVF & WINED3DFVF_PSIZE) {
4066 dest_ptr += sizeof(DWORD);
4067 if(dest_conv) dest_conv += sizeof(DWORD);
4069 if (DestFVF & WINED3DFVF_NORMAL) {
4070 float *normal =
4071 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4072 /* AFAIK this should go into the lighting information */
4073 FIXME("Didn't expect the destination to have a normal\n");
4074 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4075 if(dest_conv) {
4076 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4080 if (DestFVF & WINED3DFVF_DIFFUSE) {
4081 DWORD *color_d =
4082 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4083 if(!color_d) {
4084 static BOOL warned = FALSE;
4086 if(!warned) {
4087 ERR("No diffuse color in source, but destination has one\n");
4088 warned = TRUE;
4091 *( (DWORD *) dest_ptr) = 0xffffffff;
4092 dest_ptr += sizeof(DWORD);
4094 if(dest_conv) {
4095 *( (DWORD *) dest_conv) = 0xffffffff;
4096 dest_conv += sizeof(DWORD);
4099 else {
4100 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4101 if(dest_conv) {
4102 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4103 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4104 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4105 dest_conv += sizeof(DWORD);
4110 if (DestFVF & WINED3DFVF_SPECULAR) {
4111 /* What's the color value in the feedback buffer? */
4112 DWORD *color_s =
4113 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4114 if(!color_s) {
4115 static BOOL warned = FALSE;
4117 if(!warned) {
4118 ERR("No specular color in source, but destination has one\n");
4119 warned = TRUE;
4122 *( (DWORD *) dest_ptr) = 0xFF000000;
4123 dest_ptr += sizeof(DWORD);
4125 if(dest_conv) {
4126 *( (DWORD *) dest_conv) = 0xFF000000;
4127 dest_conv += sizeof(DWORD);
4130 else {
4131 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4132 if(dest_conv) {
4133 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4134 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4135 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4136 dest_conv += sizeof(DWORD);
4141 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4142 float *tex_coord =
4143 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4144 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4145 if(!tex_coord) {
4146 ERR("No source texture, but destination requests one\n");
4147 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4148 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4150 else {
4151 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4152 if(dest_conv) {
4153 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4159 if(dest_conv) {
4160 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4161 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4164 LEAVE_GL();
4166 return WINED3D_OK;
4168 #undef copy_and_next
4170 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4173 WineDirect3DVertexStridedData strided;
4174 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4176 if (!SrcImpl) {
4177 WARN("NULL source vertex buffer\n");
4178 return WINED3DERR_INVALIDCALL;
4180 /* We don't need the source vbo because this buffer is only used as
4181 * a source for ProcessVertices. Avoid wasting resources by converting the
4182 * buffer and loading the VBO
4184 if(SrcImpl->vbo) {
4185 TRACE("Releasing the source vbo, it won't be needed\n");
4187 if(!SrcImpl->resource.allocatedMemory) {
4188 /* Rescue the data from the buffer */
4189 void *src;
4190 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4191 if(!SrcImpl->resource.allocatedMemory) {
4192 ERR("Out of memory\n");
4193 return E_OUTOFMEMORY;
4196 ENTER_GL();
4197 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4198 checkGLcall("glBindBufferARB");
4200 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4201 if(src) {
4202 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4205 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4206 checkGLcall("glUnmapBufferARB");
4207 } else {
4208 ENTER_GL();
4211 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4212 checkGLcall("glBindBufferARB");
4213 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4214 checkGLcall("glDeleteBuffersARB");
4215 LEAVE_GL();
4217 SrcImpl->vbo = 0;
4220 memset(&strided, 0, sizeof(strided));
4221 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4223 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4226 /*****
4227 * Get / Set Texture Stage States
4228 * TODO: Verify against dx9 definitions
4229 *****/
4230 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4232 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4234 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4236 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4238 /* Reject invalid texture units */
4239 if (Stage >= GL_LIMITS(texture_stages)) {
4240 TRACE("Attempt to access invalid texture rejected\n");
4241 return WINED3DERR_INVALIDCALL;
4244 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4245 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4246 This->updateStateBlock->textureState[Stage][Type] = Value;
4248 if (This->isRecordingState) {
4249 TRACE("Recording... not performing anything\n");
4250 return WINED3D_OK;
4253 /* Checked after the assignments to allow proper stateblock recording */
4254 if(oldValue == Value) {
4255 TRACE("App is setting the old value over, nothing to do\n");
4256 return WINED3D_OK;
4259 if(Stage > This->stateBlock->lowest_disabled_stage &&
4260 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4261 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4262 * Changes in other states are important on disabled stages too
4264 return WINED3D_OK;
4267 if(Type == WINED3DTSS_COLOROP) {
4268 int i;
4270 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4271 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4272 * they have to be disabled
4274 * The current stage is dirtified below.
4276 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4277 TRACE("Additionally dirtifying stage %d\n", i);
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4280 This->stateBlock->lowest_disabled_stage = Stage;
4281 TRACE("New lowest disabled: %d\n", Stage);
4282 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4283 /* Previously disabled stage enabled. Stages above it may need enabling
4284 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4285 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4287 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4290 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4291 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4292 break;
4294 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4297 This->stateBlock->lowest_disabled_stage = i;
4298 TRACE("New lowest disabled: %d\n", i);
4300 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4301 /* TODO: Built a stage -> texture unit mapping for register combiners */
4305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4307 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4308 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4309 * will call FindTexUnitMap too.
4311 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4312 IWineD3DDeviceImpl_FindTexUnitMap(This);
4314 return WINED3D_OK;
4317 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4320 *pValue = This->updateStateBlock->textureState[Stage][Type];
4321 return WINED3D_OK;
4324 /*****
4325 * Get / Set Texture
4326 *****/
4327 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4330 IWineD3DBaseTexture *oldTexture;
4332 oldTexture = This->updateStateBlock->textures[Stage];
4333 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4335 #if 0 /* TODO: check so vertex textures */
4336 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4337 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4338 return WINED3D_OK;
4340 #endif
4342 /* Reject invalid texture units */
4343 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4344 WARN("Attempt to access invalid texture rejected\n");
4345 return WINED3DERR_INVALIDCALL;
4348 if(pTexture != NULL) {
4349 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4351 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4352 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4353 return WINED3DERR_INVALIDCALL;
4355 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4358 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4359 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4361 This->updateStateBlock->set.textures[Stage] = TRUE;
4362 This->updateStateBlock->changed.textures[Stage] = TRUE;
4363 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4364 This->updateStateBlock->textures[Stage] = pTexture;
4366 /* Handle recording of state blocks */
4367 if (This->isRecordingState) {
4368 TRACE("Recording... not performing anything\n");
4369 return WINED3D_OK;
4372 if(oldTexture == pTexture) {
4373 TRACE("App is setting the same texture again, nothing to do\n");
4374 return WINED3D_OK;
4377 /** NOTE: MSDN says that setTexture increases the reference count,
4378 * and the the application nust set the texture back to null (or have a leaky application),
4379 * This means we should pass the refcount up to the parent
4380 *******************************/
4381 if (NULL != This->updateStateBlock->textures[Stage]) {
4382 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4383 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4385 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4386 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4387 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4388 * so the COLOROP and ALPHAOP have to be dirtified.
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4393 if(bindCount == 1) {
4394 new->baseTexture.sampler = Stage;
4396 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4400 if (NULL != oldTexture) {
4401 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4402 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4404 IWineD3DBaseTexture_Release(oldTexture);
4405 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4410 if(bindCount && old->baseTexture.sampler == Stage) {
4411 int i;
4412 /* Have to do a search for the other sampler(s) where the texture is bound to
4413 * Shouldn't happen as long as apps bind a texture only to one stage
4415 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4416 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4417 if(This->updateStateBlock->textures[i] == oldTexture) {
4418 old->baseTexture.sampler = i;
4419 break;
4425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4427 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4428 * pixel shader is used
4430 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4431 IWineD3DDeviceImpl_FindTexUnitMap(This);
4434 return WINED3D_OK;
4437 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4441 /* Reject invalid texture units */
4442 if (Stage >= GL_LIMITS(sampler_stages)) {
4443 TRACE("Attempt to access invalid texture rejected\n");
4444 return WINED3DERR_INVALIDCALL;
4446 *ppTexture=This->stateBlock->textures[Stage];
4447 if (*ppTexture)
4448 IWineD3DBaseTexture_AddRef(*ppTexture);
4450 return WINED3D_OK;
4453 /*****
4454 * Get Back Buffer
4455 *****/
4456 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4457 IWineD3DSurface **ppBackBuffer) {
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 IWineD3DSwapChain *swapChain;
4460 HRESULT hr;
4462 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4464 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4465 if (hr == WINED3D_OK) {
4466 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4467 IWineD3DSwapChain_Release(swapChain);
4468 } else {
4469 *ppBackBuffer = NULL;
4471 return hr;
4474 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 WARN("(%p) : stub, calling idirect3d for now\n", This);
4477 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4480 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4482 IWineD3DSwapChain *swapChain;
4483 HRESULT hr;
4485 if(iSwapChain > 0) {
4486 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4487 if (hr == WINED3D_OK) {
4488 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4489 IWineD3DSwapChain_Release(swapChain);
4490 } else {
4491 FIXME("(%p) Error getting display mode\n", This);
4493 } else {
4494 /* Don't read the real display mode,
4495 but return the stored mode instead. X11 can't change the color
4496 depth, and some apps are pretty angry if they SetDisplayMode from
4497 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4499 Also don't relay to the swapchain because with ddraw it's possible
4500 that there isn't a swapchain at all */
4501 pMode->Width = This->ddraw_width;
4502 pMode->Height = This->ddraw_height;
4503 pMode->Format = This->ddraw_format;
4504 pMode->RefreshRate = 0;
4505 hr = WINED3D_OK;
4508 return hr;
4511 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 TRACE("(%p)->(%p)\n", This, hWnd);
4515 This->ddraw_window = hWnd;
4516 return WINED3D_OK;
4519 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 TRACE("(%p)->(%p)\n", This, hWnd);
4523 *hWnd = This->ddraw_window;
4524 return WINED3D_OK;
4527 /*****
4528 * Stateblock related functions
4529 *****/
4531 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4533 IWineD3DStateBlockImpl *object;
4534 HRESULT temp_result;
4536 TRACE("(%p)\n", This);
4538 if (This->isRecordingState) {
4539 return WINED3DERR_INVALIDCALL;
4542 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4543 if (NULL == object ) {
4544 FIXME("(%p)Error allocating memory for stateblock\n", This);
4545 return E_OUTOFMEMORY;
4547 TRACE("(%p) created object %p\n", This, object);
4548 object->wineD3DDevice= This;
4549 /** FIXME: object->parent = parent; **/
4550 object->parent = NULL;
4551 object->blockType = WINED3DSBT_ALL;
4552 object->ref = 1;
4553 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4555 temp_result = allocate_shader_constants(object);
4556 if (WINED3D_OK != temp_result)
4557 return temp_result;
4559 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4560 This->updateStateBlock = object;
4561 This->isRecordingState = TRUE;
4563 TRACE("(%p) recording stateblock %p\n",This , object);
4564 return WINED3D_OK;
4567 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4570 if (!This->isRecordingState) {
4571 FIXME("(%p) not recording! returning error\n", This);
4572 *ppStateBlock = NULL;
4573 return WINED3DERR_INVALIDCALL;
4576 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4577 This->isRecordingState = FALSE;
4578 This->updateStateBlock = This->stateBlock;
4579 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4580 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4581 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4582 return WINED3D_OK;
4585 /*****
4586 * Scene related functions
4587 *****/
4588 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4589 /* At the moment we have no need for any functionality at the beginning
4590 of a scene */
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 TRACE("(%p) : stub\n", This);
4593 return WINED3D_OK;
4596 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 TRACE("(%p)\n", This);
4599 ENTER_GL();
4600 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4601 glFlush();
4602 checkGLcall("glFlush");
4604 TRACE("End Scene\n");
4605 /* If we're using FBOs this isn't needed */
4606 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4608 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4609 IUnknown *targetContainer = NULL;
4610 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4611 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4612 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4613 /** always dirtify for now. we must find a better way to see that surface have been modified
4614 (Modifications should will only occur via draw-primitive, but we do need better locking
4615 switching to render-to-texture should remove the overhead though.
4617 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4618 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4619 IWineD3DSurface_PreLoad(This->render_targets[0]);
4620 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4621 IUnknown_Release(targetContainer);
4624 This->sceneEnded = TRUE;
4625 LEAVE_GL();
4626 return WINED3D_OK;
4629 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4630 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4631 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 IWineD3DSwapChain *swapChain = NULL;
4634 int i;
4635 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4637 TRACE("(%p) Presenting the frame\n", This);
4639 for(i = 0 ; i < swapchains ; i ++) {
4641 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4642 TRACE("presentinng chain %d, %p\n", i, swapChain);
4643 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4644 IWineD3DSwapChain_Release(swapChain);
4647 return WINED3D_OK;
4650 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4651 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4654 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4655 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4656 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4657 GLbitfield glMask = 0;
4658 GLboolean old_ztest;
4659 GLfloat old_z_clear_value;
4660 GLint old_stencil_clear_value;
4661 GLfloat old_color_clear_value[4];
4662 unsigned int i;
4663 CONST WINED3DRECT* curRect;
4665 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4666 Count, pRects, Flags, Z, Stencil);
4668 ENTER_GL();
4670 glEnable(GL_SCISSOR_TEST);
4671 checkGLcall("glEnable GL_SCISSOR_TEST");
4673 if (Count > 0 && pRects) {
4674 curRect = pRects;
4675 } else {
4676 curRect = NULL;
4679 /* Only set the values up once, as they are not changing */
4680 if (Flags & WINED3DCLEAR_STENCIL) {
4681 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4682 glClearStencil(Stencil);
4683 checkGLcall("glClearStencil");
4684 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4685 glStencilMask(0xFFFFFFFF);
4688 if (Flags & WINED3DCLEAR_ZBUFFER) {
4689 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4690 glDepthMask(GL_TRUE);
4691 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4692 glClearDepth(Z);
4693 checkGLcall("glClearDepth");
4694 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4697 if (Flags & WINED3DCLEAR_TARGET) {
4698 TRACE("Clearing screen with glClear to color %x\n", Color);
4699 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4700 glClearColor(D3DCOLOR_R(Color),
4701 D3DCOLOR_G(Color),
4702 D3DCOLOR_B(Color),
4703 D3DCOLOR_A(Color));
4704 checkGLcall("glClearColor");
4706 /* Clear ALL colors! */
4707 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4708 glMask = glMask | GL_COLOR_BUFFER_BIT;
4711 /* Now process each rect in turn */
4712 for (i = 0; i < Count || i == 0; i++) {
4714 if (curRect) {
4715 /* Note gl uses lower left, width/height */
4716 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4717 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4718 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4719 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4720 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4721 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4722 checkGLcall("glScissor");
4723 } else {
4724 glScissor(This->stateBlock->viewport.X,
4725 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4726 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4727 This->stateBlock->viewport.Width,
4728 This->stateBlock->viewport.Height);
4729 checkGLcall("glScissor");
4732 /* Clear the selected rectangle (or full screen) */
4733 glClear(glMask);
4734 checkGLcall("glClear");
4736 /* Step to the next rectangle */
4737 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4740 /* Restore the old values (why..?) */
4741 if (Flags & WINED3DCLEAR_STENCIL) {
4742 glClearStencil(old_stencil_clear_value);
4743 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4745 if (Flags & WINED3DCLEAR_ZBUFFER) {
4746 glDepthMask(old_ztest);
4747 glClearDepth(old_z_clear_value);
4749 if (Flags & WINED3DCLEAR_TARGET) {
4750 glClearColor(old_color_clear_value[0],
4751 old_color_clear_value[1],
4752 old_color_clear_value[2],
4753 old_color_clear_value[3]);
4754 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4755 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4756 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4757 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4760 glDisable(GL_SCISSOR_TEST);
4761 checkGLcall("glDisable");
4762 LEAVE_GL();
4764 return WINED3D_OK;
4767 /*****
4768 * Drawing functions
4769 *****/
4770 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4771 UINT PrimitiveCount) {
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4774 This->stateBlock->streamIsUP = FALSE;
4776 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4777 debug_d3dprimitivetype(PrimitiveType),
4778 StartVertex, PrimitiveCount);
4779 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4780 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
4783 return WINED3D_OK;
4786 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4787 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4788 WINED3DPRIMITIVETYPE PrimitiveType,
4789 INT baseVIndex, UINT minIndex,
4790 UINT NumVertices, UINT startIndex, UINT primCount) {
4792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4793 UINT idxStride = 2;
4794 IWineD3DIndexBuffer *pIB;
4795 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4797 pIB = This->stateBlock->pIndexData;
4798 This->stateBlock->streamIsUP = FALSE;
4800 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
4801 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4802 minIndex, NumVertices, startIndex, baseVIndex, primCount);
4804 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4805 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4806 idxStride = 2;
4807 } else {
4808 idxStride = 4;
4811 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
4812 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
4814 return WINED3D_OK;
4817 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4818 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4819 UINT VertexStreamZeroStride) {
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4822 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4823 debug_d3dprimitivetype(PrimitiveType),
4824 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4826 /* release the stream source */
4827 if (This->stateBlock->streamSource[0] != NULL) {
4828 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4831 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4832 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4833 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4834 This->stateBlock->streamIsUP = TRUE;
4836 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4837 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
4839 /* MSDN specifies stream zero settings must be set to NULL */
4840 This->stateBlock->streamStride[0] = 0;
4841 This->stateBlock->streamSource[0] = NULL;
4843 /*stream zero settings set to null at end, as per the msdn */
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4848 UINT MinVertexIndex, UINT NumVertices,
4849 UINT PrimitiveCount, CONST void* pIndexData,
4850 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4851 UINT VertexStreamZeroStride) {
4852 int idxStride;
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4856 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4857 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4858 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4860 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4861 idxStride = 2;
4862 } else {
4863 idxStride = 4;
4866 /* release the stream and index data */
4867 if (This->stateBlock->streamSource[0] != NULL) {
4868 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4870 if (This->stateBlock->pIndexData) {
4871 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
4874 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4875 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4876 This->stateBlock->streamIsUP = TRUE;
4877 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4879 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
4881 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4882 This->stateBlock->streamSource[0] = NULL;
4883 This->stateBlock->streamStride[0] = 0;
4884 This->stateBlock->pIndexData = NULL;
4886 return WINED3D_OK;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4891 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
4892 return WINED3D_OK;
4894 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4895 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 HRESULT hr = WINED3D_OK;
4898 WINED3DRESOURCETYPE sourceType;
4899 WINED3DRESOURCETYPE destinationType;
4900 int i ,levels;
4902 /* TODO: think about moving the code into IWineD3DBaseTexture */
4904 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4906 /* verify that the source and destination textures aren't NULL */
4907 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4908 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4909 This, pSourceTexture, pDestinationTexture);
4910 hr = WINED3DERR_INVALIDCALL;
4913 if (pSourceTexture == pDestinationTexture) {
4914 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4915 This, pSourceTexture, pDestinationTexture);
4916 hr = WINED3DERR_INVALIDCALL;
4918 /* Verify that the source and destination textures are the same type */
4919 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4920 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4922 if (sourceType != destinationType) {
4923 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4924 This);
4925 hr = WINED3DERR_INVALIDCALL;
4928 /* check that both textures have the identical numbers of levels */
4929 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4930 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4931 hr = WINED3DERR_INVALIDCALL;
4934 if (WINED3D_OK == hr) {
4936 /* Make sure that the destination texture is loaded */
4937 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4939 /* Update every surface level of the texture */
4940 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4942 switch (sourceType) {
4943 case WINED3DRTYPE_TEXTURE:
4945 IWineD3DSurface *srcSurface;
4946 IWineD3DSurface *destSurface;
4948 for (i = 0 ; i < levels ; ++i) {
4949 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4950 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4951 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4952 IWineD3DSurface_Release(srcSurface);
4953 IWineD3DSurface_Release(destSurface);
4954 if (WINED3D_OK != hr) {
4955 WARN("(%p) : Call to update surface failed\n", This);
4956 return hr;
4960 break;
4961 case WINED3DRTYPE_CUBETEXTURE:
4963 IWineD3DSurface *srcSurface;
4964 IWineD3DSurface *destSurface;
4965 WINED3DCUBEMAP_FACES faceType;
4967 for (i = 0 ; i < levels ; ++i) {
4968 /* Update each cube face */
4969 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4970 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4971 if (WINED3D_OK != hr) {
4972 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4973 } else {
4974 TRACE("Got srcSurface %p\n", srcSurface);
4976 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4977 if (WINED3D_OK != hr) {
4978 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4979 } else {
4980 TRACE("Got desrSurface %p\n", destSurface);
4982 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4983 IWineD3DSurface_Release(srcSurface);
4984 IWineD3DSurface_Release(destSurface);
4985 if (WINED3D_OK != hr) {
4986 WARN("(%p) : Call to update surface failed\n", This);
4987 return hr;
4992 break;
4993 #if 0 /* TODO: Add support for volume textures */
4994 case WINED3DRTYPE_VOLUMETEXTURE:
4996 IWineD3DVolume srcVolume = NULL;
4997 IWineD3DSurface destVolume = NULL;
4999 for (i = 0 ; i < levels ; ++i) {
5000 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5001 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5002 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5003 IWineD3DVolume_Release(srcSurface);
5004 IWineD3DVolume_Release(destSurface);
5005 if (WINED3D_OK != hr) {
5006 WARN("(%p) : Call to update volume failed\n", This);
5007 return hr;
5011 break;
5012 #endif
5013 default:
5014 FIXME("(%p) : Unsupported source and destination type\n", This);
5015 hr = WINED3DERR_INVALIDCALL;
5019 return hr;
5022 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5023 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5024 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 TRACE("(%p) : stub\n", This);
5028 return WINED3D_OK;
5030 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5032 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5033 * NOTE It may be best to move the code into surface to occomplish this
5034 ****************************************/
5036 WINED3DSURFACE_DESC surfaceDesc;
5037 unsigned int surfaceWidth, surfaceHeight;
5038 glDescriptor *targetGlDescription = NULL;
5039 glDescriptor *surfaceGlDescription = NULL;
5040 IWineD3DSwapChainImpl *container = NULL;
5042 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5043 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5044 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5046 surfaceDesc.Width = &surfaceWidth;
5047 surfaceDesc.Height = &surfaceHeight;
5048 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5049 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5051 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5052 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5053 ENTER_GL();
5054 /* TODO: opengl Context switching for swapchains etc... */
5055 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
5056 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
5057 glReadBuffer(GL_BACK);
5058 vcheckGLcall("glReadBuffer(GL_BACK)");
5059 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
5060 glReadBuffer(GL_FRONT);
5061 vcheckGLcall("glReadBuffer(GL_FRONT)");
5062 } else if (pRenderTarget == This->depthStencilBuffer) {
5063 FIXME("Reading of depthstencil not yet supported\n");
5066 glReadPixels(0,
5068 surfaceWidth,
5069 surfaceHeight,
5070 surfaceGlDescription->glFormat,
5071 surfaceGlDescription->glType,
5072 (void *)IWineD3DSurface_GetData(pSurface));
5073 vcheckGLcall("glReadPixels(...)");
5074 if(NULL != container ){
5075 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5077 } else {
5078 IWineD3DBaseTexture *container;
5079 GLenum textureDimensions = GL_TEXTURE_2D;
5081 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5082 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5083 IWineD3DBaseTexture_Release(container);
5085 /* TODO: 2D -> Cube surface coppies etc.. */
5086 if (surfaceGlDescription->target != textureDimensions) {
5087 FIXME("(%p) : Texture dimension mismatch\n", This);
5089 glEnable(textureDimensions);
5090 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5091 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5092 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5093 vcheckGLcall("glBindTexture");
5094 glGetTexImage(surfaceGlDescription->target,
5095 surfaceGlDescription->level,
5096 surfaceGlDescription->glFormat,
5097 surfaceGlDescription->glType,
5098 (void *)IWineD3DSurface_GetData(pSurface));
5099 glDisable(textureDimensions);
5100 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5103 LEAVE_GL();
5104 return WINED3D_OK;
5107 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5108 IWineD3DSwapChain *swapChain;
5109 HRESULT hr;
5110 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5111 if(hr == WINED3D_OK) {
5112 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5113 IWineD3DSwapChain_Release(swapChain);
5115 return hr;
5118 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 /* return a sensible default */
5121 *pNumPasses = 1;
5122 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5123 FIXME("(%p) : stub\n", This);
5124 return WINED3D_OK;
5127 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 int j;
5130 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5131 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5132 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5133 return WINED3DERR_INVALIDCALL;
5135 for (j = 0; j < 256; ++j) {
5136 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5137 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5138 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5139 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5141 TRACE("(%p) : returning\n", This);
5142 return WINED3D_OK;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5147 int j;
5148 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5149 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5150 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5151 return WINED3DERR_INVALIDCALL;
5153 for (j = 0; j < 256; ++j) {
5154 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5155 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5156 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5157 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5159 TRACE("(%p) : returning\n", This);
5160 return WINED3D_OK;
5163 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5166 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5167 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5168 return WINED3DERR_INVALIDCALL;
5170 /*TODO: stateblocks */
5171 This->currentPalette = PaletteNumber;
5172 TRACE("(%p) : returning\n", This);
5173 return WINED3D_OK;
5176 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5178 if (PaletteNumber == NULL) {
5179 WARN("(%p) : returning Invalid Call\n", This);
5180 return WINED3DERR_INVALIDCALL;
5182 /*TODO: stateblocks */
5183 *PaletteNumber = This->currentPalette;
5184 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5185 return WINED3D_OK;
5188 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5190 static BOOL showFixmes = TRUE;
5191 if (showFixmes) {
5192 FIXME("(%p) : stub\n", This);
5193 showFixmes = FALSE;
5196 This->softwareVertexProcessing = bSoftware;
5197 return WINED3D_OK;
5201 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 static BOOL showFixmes = TRUE;
5204 if (showFixmes) {
5205 FIXME("(%p) : stub\n", This);
5206 showFixmes = FALSE;
5208 return This->softwareVertexProcessing;
5212 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5214 IWineD3DSwapChain *swapChain;
5215 HRESULT hr;
5217 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5219 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5220 if(hr == WINED3D_OK){
5221 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5222 IWineD3DSwapChain_Release(swapChain);
5223 }else{
5224 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5226 return hr;
5230 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 static BOOL showfixmes = TRUE;
5233 if(nSegments != 0.0f) {
5234 if( showfixmes) {
5235 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5236 showfixmes = FALSE;
5239 return WINED3D_OK;
5242 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5244 static BOOL showfixmes = TRUE;
5245 if( showfixmes) {
5246 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5247 showfixmes = FALSE;
5249 return 0.0f;
5252 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5254 /** TODO: remove casts to IWineD3DSurfaceImpl
5255 * NOTE: move code to surface to accomplish this
5256 ****************************************/
5257 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5258 int srcWidth, srcHeight;
5259 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5260 WINED3DFORMAT destFormat, srcFormat;
5261 UINT destSize;
5262 int destLeft, destTop;
5263 WINED3DPOOL srcPool, destPool;
5264 int offset = 0;
5265 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5266 glDescriptor *glDescription = NULL;
5267 GLenum textureDimensions = GL_TEXTURE_2D;
5268 IWineD3DBaseTexture *baseTexture;
5270 WINED3DSURFACE_DESC winedesc;
5272 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5273 memset(&winedesc, 0, sizeof(winedesc));
5274 winedesc.Width = &srcSurfaceWidth;
5275 winedesc.Height = &srcSurfaceHeight;
5276 winedesc.Pool = &srcPool;
5277 winedesc.Format = &srcFormat;
5279 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5281 winedesc.Width = &destSurfaceWidth;
5282 winedesc.Height = &destSurfaceHeight;
5283 winedesc.Pool = &destPool;
5284 winedesc.Format = &destFormat;
5285 winedesc.Size = &destSize;
5287 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5289 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5290 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5291 return WINED3DERR_INVALIDCALL;
5294 if (destFormat == WINED3DFMT_UNKNOWN) {
5295 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5296 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5298 /* Get the update surface description */
5299 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5302 /* Make sure the surface is loaded and up to date */
5303 IWineD3DSurface_PreLoad(pDestinationSurface);
5305 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5307 ENTER_GL();
5309 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5310 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5311 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5312 destLeft = pDestPoint ? pDestPoint->x : 0;
5313 destTop = pDestPoint ? pDestPoint->y : 0;
5316 /* This function doesn't support compressed textures
5317 the pitch is just bytesPerPixel * width */
5318 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5319 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5320 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5321 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5323 /* TODO DXT formats */
5325 if(pSourceRect != NULL && pSourceRect->top != 0){
5326 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5328 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5329 ,This
5330 ,glDescription->level
5331 ,destLeft
5332 ,destTop
5333 ,srcWidth
5334 ,srcHeight
5335 ,glDescription->glFormat
5336 ,glDescription->glType
5337 ,IWineD3DSurface_GetData(pSourceSurface)
5340 /* Sanity check */
5341 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5343 /* need to lock the surface to get the data */
5344 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5347 /* TODO: Cube and volume support */
5348 if(rowoffset != 0){
5349 /* not a whole row so we have to do it a line at a time */
5350 int j;
5352 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5353 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5355 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5357 glTexSubImage2D(glDescription->target
5358 ,glDescription->level
5359 ,destLeft
5361 ,srcWidth
5363 ,glDescription->glFormat
5364 ,glDescription->glType
5365 ,data /* could be quicker using */
5367 data += rowoffset;
5370 } else { /* Full width, so just write out the whole texture */
5372 if (WINED3DFMT_DXT1 == destFormat ||
5373 WINED3DFMT_DXT2 == destFormat ||
5374 WINED3DFMT_DXT3 == destFormat ||
5375 WINED3DFMT_DXT4 == destFormat ||
5376 WINED3DFMT_DXT5 == destFormat) {
5377 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5378 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5379 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5380 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5381 } if (destFormat != srcFormat) {
5382 FIXME("Updating mixed format compressed texture is not curretly support\n");
5383 } else {
5384 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5385 glDescription->level,
5386 glDescription->glFormatInternal,
5387 srcWidth,
5388 srcHeight,
5390 destSize,
5391 IWineD3DSurface_GetData(pSourceSurface));
5393 } else {
5394 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5398 } else {
5399 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5401 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5402 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5403 data returned by GetData non-power2 width/height with hardware non-power2
5404 pow2Width/height are set to surface width height, repacking isn't needed so it
5405 doesn't matter which function gets called. */
5406 glTexSubImage2D(glDescription->target
5407 ,glDescription->level
5408 ,destLeft
5409 ,destTop
5410 ,srcWidth
5411 ,srcHeight
5412 ,glDescription->glFormat
5413 ,glDescription->glType
5414 ,IWineD3DSurface_GetData(pSourceSurface)
5416 } else {
5418 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5419 glTexSubImage2D(glDescription->target
5420 ,glDescription->level
5421 ,destLeft
5422 ,destTop
5423 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5424 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5425 ,glDescription->glFormat
5426 ,glDescription->glType
5427 ,IWineD3DSurface_GetData(pSourceSurface)
5433 checkGLcall("glTexSubImage2D");
5434 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5436 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5437 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5438 * surface bigger than it needs to be hmm.. */
5439 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5440 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5441 IWineD3DBaseTexture_Release(baseTexture);
5444 glDisable(textureDimensions); /* This needs to be managed better.... */
5445 LEAVE_GL();
5447 return WINED3D_OK;
5450 /* Implementation details at http://developer.nvidia.com/attach/6494
5452 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5453 hmm.. no longer supported use
5454 OpenGL evaluators or tessellate surfaces within your application.
5457 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5458 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5460 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5461 FIXME("(%p) : Stub\n", This);
5462 return WINED3D_OK;
5466 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5467 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5469 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5470 FIXME("(%p) : Stub\n", This);
5471 return WINED3D_OK;
5474 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5476 TRACE("(%p) Handle(%d)\n", This, Handle);
5477 FIXME("(%p) : Stub\n", This);
5478 return WINED3D_OK;
5481 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5483 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5484 DDBLTFX BltFx;
5485 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5487 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5488 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5489 return WINED3DERR_INVALIDCALL;
5492 /* Just forward this to the DirectDraw blitting engine */
5493 memset(&BltFx, 0, sizeof(BltFx));
5494 BltFx.dwSize = sizeof(BltFx);
5495 BltFx.u5.dwFillColor = color;
5496 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5499 /* rendertarget and deptth stencil functions */
5500 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5503 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5504 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5505 return WINED3DERR_INVALIDCALL;
5508 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5509 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5510 /* Note inc ref on returned surface */
5511 if(*ppRenderTarget != NULL)
5512 IWineD3DSurface_AddRef(*ppRenderTarget);
5513 return WINED3D_OK;
5516 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5518 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5519 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5520 IWineD3DSwapChainImpl *Swapchain;
5521 HRESULT hr;
5523 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5525 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5526 if(hr != WINED3D_OK) {
5527 ERR("Can't get the swapchain\n");
5528 return hr;
5531 /* Make sure to release the swapchain */
5532 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5534 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5535 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5536 return WINED3DERR_INVALIDCALL;
5538 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5539 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5540 return WINED3DERR_INVALIDCALL;
5543 if(Swapchain->frontBuffer != Front) {
5544 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5546 if(Swapchain->frontBuffer)
5547 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5548 Swapchain->frontBuffer = Front;
5550 if(Swapchain->frontBuffer) {
5551 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5555 if(Back && !Swapchain->backBuffer) {
5556 /* We need memory for the back buffer array - only one back buffer this way */
5557 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5558 if(!Swapchain->backBuffer) {
5559 ERR("Out of memory\n");
5560 return E_OUTOFMEMORY;
5564 if(Swapchain->backBuffer[0] != Back) {
5565 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5566 ENTER_GL();
5567 if(!Swapchain->backBuffer[0]) {
5568 /* GL was told to draw to the front buffer at creation,
5569 * undo that
5571 glDrawBuffer(GL_BACK);
5572 checkGLcall("glDrawBuffer(GL_BACK)");
5573 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5574 Swapchain->presentParms.BackBufferCount = 1;
5575 } else if (!Back) {
5576 /* That makes problems - disable for now */
5577 /* glDrawBuffer(GL_FRONT); */
5578 checkGLcall("glDrawBuffer(GL_FRONT)");
5579 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5580 Swapchain->presentParms.BackBufferCount = 0;
5582 LEAVE_GL();
5584 if(Swapchain->backBuffer[0])
5585 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5586 Swapchain->backBuffer[0] = Back;
5588 if(Swapchain->backBuffer[0]) {
5589 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5590 } else {
5591 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5596 return WINED3D_OK;
5599 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5601 *ppZStencilSurface = This->depthStencilBuffer;
5602 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5604 if(*ppZStencilSurface != NULL) {
5605 /* Note inc ref on returned surface */
5606 IWineD3DSurface_AddRef(*ppZStencilSurface);
5608 return WINED3D_OK;
5611 static void bind_fbo(IWineD3DDevice *iface) {
5612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 if (!This->fbo) {
5615 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5616 checkGLcall("glGenFramebuffersEXT()");
5618 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5619 checkGLcall("glBindFramebuffer()");
5622 /* TODO: Handle stencil attachments */
5623 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5625 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5627 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5629 bind_fbo(iface);
5631 if (depth_stencil_impl) {
5632 GLenum texttarget, target;
5633 GLint old_binding = 0;
5635 IWineD3DSurface_PreLoad(depth_stencil);
5636 texttarget = depth_stencil_impl->glDescription.target;
5637 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5639 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5640 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5641 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5642 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5643 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5644 glBindTexture(target, old_binding);
5646 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5647 checkGLcall("glFramebufferTexture2DEXT()");
5648 } else {
5649 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5650 checkGLcall("glFramebufferTexture2DEXT()");
5653 if (!This->render_offscreen) {
5654 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5655 checkGLcall("glBindFramebuffer()");
5659 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5663 if (idx >= GL_LIMITS(buffers)) {
5664 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5667 bind_fbo(iface);
5669 if (rtimpl) {
5670 GLenum texttarget, target;
5671 GLint old_binding = 0;
5673 IWineD3DSurface_PreLoad(render_target);
5674 texttarget = rtimpl->glDescription.target;
5675 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5677 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5678 glBindTexture(target, rtimpl->glDescription.textureName);
5679 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5680 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5681 glBindTexture(target, old_binding);
5683 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5684 checkGLcall("glFramebufferTexture2DEXT()");
5686 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5687 } else {
5688 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5689 checkGLcall("glFramebufferTexture2DEXT()");
5691 This->draw_buffers[idx] = GL_NONE;
5694 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5695 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5696 checkGLcall("glDrawBuffers()");
5699 if (!This->render_offscreen) {
5700 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5701 checkGLcall("glBindFramebuffer()");
5705 /* internal static helper functions */
5706 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5707 IWineD3DSurface *RenderSurface);
5709 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5711 HRESULT hr = WINED3D_OK;
5712 WINED3DVIEWPORT viewport;
5714 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5716 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5717 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5718 return WINED3DERR_INVALIDCALL;
5721 /* MSDN says that null disables the render target
5722 but a device must always be associated with a render target
5723 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5725 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5726 for more details
5728 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5729 FIXME("Trying to set render target 0 to NULL\n");
5730 return WINED3DERR_INVALIDCALL;
5732 /* TODO: replace Impl* usage with interface usage */
5733 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5734 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);
5735 return WINED3DERR_INVALIDCALL;
5737 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5738 * builds, but I think wine counts as a 'debug' build for now.
5739 ******************************/
5740 /* If we are trying to set what we already have, don't bother */
5741 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5742 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5743 } else {
5744 /* Otherwise, set the render target up */
5746 if (!This->sceneEnded) {
5747 IWineD3DDevice_EndScene(iface);
5749 TRACE("clearing renderer\n");
5750 /* IWineD3DDeviceImpl_CleanRender(iface); */
5751 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5752 depending on the renter target implementation being used.
5753 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5754 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5755 stencil buffer and incure an extra memory overhead */
5756 if (RenderTargetIndex == 0) {
5757 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5758 } else {
5759 hr = WINED3D_OK;
5762 /* Replace the render target */
5763 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5764 This->render_targets[RenderTargetIndex] = pRenderTarget;
5765 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5767 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5768 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5772 if (SUCCEEDED(hr)) {
5773 /* Finally, reset the viewport as the MSDN states. */
5774 /* TODO: Replace impl usage */
5775 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5776 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5777 viewport.X = 0;
5778 viewport.Y = 0;
5779 viewport.MaxZ = 1.0f;
5780 viewport.MinZ = 0.0f;
5781 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5782 } else {
5783 FIXME("Unknown error setting the render target\n");
5785 This->sceneEnded = FALSE;
5786 return hr;
5789 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5791 HRESULT hr = WINED3D_OK;
5792 IWineD3DSurface *tmp;
5794 TRACE("(%p) Swapping z-buffer\n",This);
5796 if (pNewZStencil == This->stencilBufferTarget) {
5797 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5798 } else {
5799 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5800 * depending on the renter target implementation being used.
5801 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5802 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5803 * stencil buffer and incure an extra memory overhead
5804 ******************************************************/
5807 tmp = This->stencilBufferTarget;
5808 This->stencilBufferTarget = pNewZStencil;
5809 /* should we be calling the parent or the wined3d surface? */
5810 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5811 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5812 hr = WINED3D_OK;
5813 /** TODO: glEnable/glDisable on depth/stencil depending on
5814 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5815 **********************************************************/
5816 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5817 set_depth_stencil_fbo(iface, pNewZStencil);
5821 return hr;
5825 #ifdef GL_VERSION_1_3
5826 /* Internal functions not in DirectX */
5827 /** TODO: move this off to the opengl context manager
5828 *(the swapchain doesn't need to know anything about offscreen rendering!)
5829 ****************************************************/
5831 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 TRACE("(%p), %p\n", This, swapchain);
5837 if (swapchain->win != swapchain->drawable) {
5838 /* Set everything back the way it ws */
5839 swapchain->render_ctx = swapchain->glCtx;
5840 swapchain->drawable = swapchain->win;
5842 return WINED3D_OK;
5845 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5846 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5848 int i;
5849 unsigned int width;
5850 unsigned int height;
5851 WINED3DFORMAT format;
5852 WINED3DSURFACE_DESC surfaceDesc;
5853 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5854 surfaceDesc.Width = &width;
5855 surfaceDesc.Height = &height;
5856 surfaceDesc.Format = &format;
5857 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5858 *context = NULL;
5859 /* I need a get width/height function (and should do something with the format) */
5860 for (i = 0; i < CONTEXT_CACHE; ++i) {
5861 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5862 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5863 the pSurface can be set to 0 allowing it to be reused from cache **/
5864 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5865 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5866 *context = &This->contextCache[i];
5867 break;
5869 if (This->contextCache[i].Width == 0) {
5870 This->contextCache[i].pSurface = pSurface;
5871 This->contextCache[i].Width = width;
5872 This->contextCache[i].Height = height;
5873 *context = &This->contextCache[i];
5874 break;
5877 if (i == CONTEXT_CACHE) {
5878 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5879 glContext *dropContext = 0;
5880 for (i = 0; i < CONTEXT_CACHE; i++) {
5881 if (This->contextCache[i].usedcount < minUsage) {
5882 dropContext = &This->contextCache[i];
5883 minUsage = This->contextCache[i].usedcount;
5886 /* clean up the context (this doesn't work for ATI at the moment */
5887 #if 0
5888 glXDestroyContext(swapchain->display, dropContext->context);
5889 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5890 #endif
5891 FIXME("Leak\n");
5892 dropContext->Width = 0;
5893 dropContext->pSurface = pSurface;
5894 *context = dropContext;
5895 } else {
5896 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5897 for (i = 0; i < CONTEXT_CACHE; i++) {
5898 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5902 if (*context != NULL)
5903 return WINED3D_OK;
5904 else
5905 return E_OUTOFMEMORY;
5907 #endif
5909 /* Reapply the device stateblock */
5910 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
5912 BOOL oldRecording;
5913 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5914 DWORD i;
5916 /* Disable recording */
5917 oldUpdateStateBlock = This->updateStateBlock;
5918 oldRecording= This->isRecordingState;
5919 This->isRecordingState = FALSE;
5920 This->updateStateBlock = This->stateBlock;
5922 /* Reapply the state block */
5923 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
5925 /* Temporaryily mark all render states dirty to force reapplication
5926 * until the context management for is integrated with the state management
5927 * The same for the pixel shader, sampler states and texture stage states are marked
5928 * dirty my StateBlock::Apply already
5930 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
5931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
5933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5935 /* Restore recording */
5936 This->isRecordingState = oldRecording;
5937 This->updateStateBlock = oldUpdateStateBlock;
5940 /* Set offscreen rendering. When rendering offscreen the surface will be
5941 * rendered upside down to compensate for the fact that D3D texture coordinates
5942 * are flipped compared to GL texture coordinates. The cullmode is affected by
5943 * this, so it must be updated. To update the cullmode stateblock recording has
5944 * to be temporarily disabled. The new state management code will hopefully
5945 * make this unnecessary */
5946 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
5948 BOOL oldRecording;
5949 IWineD3DStateBlockImpl *oldUpdateStateBlock;
5951 /* Nothing to update, return. */
5952 if (This->render_offscreen == isTexture) return;
5954 /* Disable recording */
5955 oldUpdateStateBlock = This->updateStateBlock;
5956 oldRecording= This->isRecordingState;
5957 This->isRecordingState = FALSE;
5958 This->updateStateBlock = This->stateBlock;
5960 This->render_offscreen = isTexture;
5961 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
5962 This->depth_copy_state = WINED3D_DCS_COPY;
5964 This->last_was_rhw = FALSE;
5965 This->proj_valid = FALSE;
5966 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
5968 /* Restore recording */
5969 This->isRecordingState = oldRecording;
5970 This->updateStateBlock = oldUpdateStateBlock;
5973 /* Returns an array of compatible FBconfig(s).
5974 * The array must be freed with XFree. Requires ENTER_GL() */
5976 static GLXFBConfig* device_find_fbconfigs(
5977 IWineD3DDeviceImpl* This,
5978 IWineD3DSwapChainImpl* implicitSwapchainImpl,
5979 IWineD3DSurface* RenderSurface) {
5981 GLXFBConfig* cfgs = NULL;
5982 int nCfgs = 0;
5983 int attribs[256];
5984 int nAttribs = 0;
5986 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5987 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5988 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5990 /**TODO:
5991 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5992 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5995 #define PUSH1(att) attribs[nAttribs++] = (att);
5996 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5998 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
6000 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
6001 PUSH2(GLX_X_RENDERABLE, TRUE);
6002 PUSH2(GLX_DOUBLEBUFFER, TRUE);
6003 TRACE("calling makeglcfg\n");
6004 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
6005 PUSH1(None);
6006 TRACE("calling chooseFGConfig\n");
6007 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6008 DefaultScreen(implicitSwapchainImpl->display),
6009 attribs, &nCfgs);
6010 if (cfgs == NULL) {
6011 /* OK we didn't find the exact config, so use any reasonable match */
6012 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
6013 why we failed. */
6014 static BOOL show_message = TRUE;
6015 if (show_message) {
6016 ERR("Failed to find exact match, finding alternative but you may "
6017 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
6018 show_message = FALSE;
6020 nAttribs = 0;
6021 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6022 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
6023 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6024 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6025 TRACE("calling makeglcfg\n");
6026 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6027 PUSH1(None);
6028 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6029 DefaultScreen(implicitSwapchainImpl->display),
6030 attribs, &nCfgs);
6033 if (cfgs == NULL) {
6034 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6035 BackBufferFormat, debug_d3dformat(BackBufferFormat),
6036 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6037 } else {
6038 #ifdef EXTRA_TRACES
6039 int i;
6040 for (i = 0; i < nCfgs; ++i) {
6041 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6042 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6043 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6045 if (NULL != This->renderTarget) {
6046 glFlush();
6047 vcheckGLcall("glFlush");
6048 /** This is only useful if the old render target was a swapchain,
6049 * we need to supercede this with a function that displays
6050 * the current buffer on the screen. This is easy to do in glx1.3 but
6051 * we need to do copy-write pixels in glx 1.2.
6052 ************************************************/
6053 glXSwapBuffers(implicitSwapChainImpl->display,
6054 implicitSwapChainImpl->drawable);
6055 printf("Hit Enter to get next frame ...\n");
6056 getchar();
6058 #endif
6060 #undef PUSH1
6061 #undef PUSH2
6063 return cfgs;
6066 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6067 * the functionality needs splitting up so that we don't do more than we should do.
6068 * this only seems to impact performance a little.
6069 ******************************/
6070 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6071 IWineD3DSurface *RenderSurface) {
6074 * Currently only active for GLX >= 1.3
6075 * for others versions we'll have to use GLXPixmaps
6077 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6078 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6079 * so only check OpenGL version
6080 * ..........................
6081 * I don't believe that it is a problem with NVidia headers,
6082 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6083 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6084 * ATI Note:
6085 * Your application will report GLX version 1.2 on glXQueryVersion.
6086 * However, it is safe to call the GLX 1.3 functions as described below.
6088 #if defined(GL_VERSION_1_3)
6090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6091 GLXFBConfig* cfgs = NULL;
6092 IWineD3DSwapChain *currentSwapchain;
6093 IWineD3DSwapChainImpl *currentSwapchainImpl;
6094 IWineD3DSwapChain *implicitSwapchain;
6095 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6096 IWineD3DSwapChain *renderSurfaceSwapchain;
6097 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6099 /* Obtain a reference to the device implicit swapchain,
6100 * the swapchain of the current render target,
6101 * and the swapchain of the new render target.
6102 * Fallback to device implicit swapchain if the current render target doesn't have one */
6103 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6104 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6105 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6106 if (currentSwapchain == NULL)
6107 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6109 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6110 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6111 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6113 ENTER_GL();
6116 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6117 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6118 **********************************************************************/
6119 if (renderSurfaceSwapchain != NULL) {
6121 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6122 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6123 TRACE("making swapchain active\n");
6124 if (RenderSurface != This->render_targets[0]) {
6125 BOOL backbuf = FALSE;
6126 int i;
6128 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6129 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6130 backbuf = TRUE;
6131 break;
6135 if (backbuf) {
6136 } else {
6137 /* This could be flagged so that some operations work directly with the front buffer */
6138 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6140 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6141 renderSurfaceSwapchainImpl->win,
6142 renderSurfaceSwapchainImpl->glCtx) == False) {
6144 TRACE("Error in setting current context: context %p drawable %ld !\n",
6145 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6147 checkGLcall("glXMakeContextCurrent");
6149 /* Clean up the old context */
6150 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6152 /* Reapply the stateblock, and set the device not to render to texture */
6153 device_reapply_stateblock(This);
6154 device_render_to_texture(This, FALSE);
6157 /* Offscreen rendering: PBuffers (currently disabled).
6158 * Also note that this path is never reached if FBOs are supported */
6159 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6160 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6162 /** ********************************************************************
6163 * This is a quickly hacked out implementation of offscreen textures.
6164 * It will work in most cases but there may be problems if the client
6165 * modifies the texture directly, or expects the contents of the rendertarget
6166 * to be persistent.
6168 * There are some real speed vs compatibility issues here:
6169 * we should really use a new context for every texture, but that eats ram.
6170 * we should also be restoring the texture to the pbuffer but that eats CPU
6171 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6172 * but if this means reusing the display backbuffer then we need to make sure that
6173 * states are correctly preserved.
6174 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6175 * and gain a good performance increase at the cost of compatibility.
6176 * I would suggest that, when this is the case, a user configurable flag be made
6177 * available, allowing the user to choose the best emulated experience for them.
6178 *********************************************************************/
6180 XVisualInfo *visinfo;
6181 glContext *newContext;
6183 /* Here were using a shared context model */
6184 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6185 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6188 /* If the context doesn't exist then create a new one */
6189 /* TODO: This should really be part of findGlContext */
6190 if (NULL == newContext->context) {
6192 int attribs[256];
6193 int nAttribs = 0;
6195 TRACE("making new buffer\n");
6196 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6197 attribs[nAttribs++] = newContext->Width;
6198 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6199 attribs[nAttribs++] = newContext->Height;
6200 attribs[nAttribs++] = None;
6202 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6204 /** ****************************************
6205 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6206 *they note:
6207 * In future releases, we may provide the calls glXCreateNewContext,
6208 * glXQueryDrawable and glXMakeContextCurrent.
6209 * so until then we have to use glXGetVisualFromFBConfig &co..
6210 ********************************************/
6212 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6213 if (!visinfo) {
6214 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6215 } else {
6216 newContext->context = glXCreateContext(
6217 implicitSwapchainImpl->display, visinfo,
6218 implicitSwapchainImpl->glCtx, GL_TRUE);
6220 XFree(visinfo);
6223 if (NULL == newContext || NULL == newContext->context) {
6224 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6225 } else {
6226 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6227 if (glXMakeCurrent(implicitSwapchainImpl->display,
6228 newContext->drawable, newContext->context) == False) {
6230 TRACE("Error in setting current context: context %p drawable %ld\n",
6231 newContext->context, newContext->drawable);
6233 checkGLcall("glXMakeContextCurrent");
6235 /* Clean up the old context */
6236 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6238 /* Reapply stateblock, and set device to render to a texture */
6239 device_reapply_stateblock(This);
6240 device_render_to_texture(This, TRUE);
6242 /* Set the current context of the swapchain to the new context */
6243 implicitSwapchainImpl->drawable = newContext->drawable;
6244 implicitSwapchainImpl->render_ctx = newContext->context;
6246 } else {
6247 /* Same context, but update render_offscreen and cull mode */
6248 device_render_to_texture(This, TRUE);
6251 if (cfgs != NULL) XFree(cfgs);
6252 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6253 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6254 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6255 LEAVE_GL();
6256 #endif
6257 return WINED3D_OK;
6260 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6261 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6263 /* TODO: the use of Impl is deprecated. */
6264 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6266 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6268 /* some basic validation checks */
6269 if(This->cursorTexture) {
6270 ENTER_GL();
6271 glDeleteTextures(1, &This->cursorTexture);
6272 LEAVE_GL();
6273 This->cursorTexture = 0;
6276 if(pCursorBitmap) {
6277 /* MSDN: Cursor must be A8R8G8B8 */
6278 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6279 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6280 return WINED3DERR_INVALIDCALL;
6283 /* MSDN: Cursor must be smaller than the display mode */
6284 if(pSur->currentDesc.Width > This->ddraw_width ||
6285 pSur->currentDesc.Height > This->ddraw_height) {
6286 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);
6287 return WINED3DERR_INVALIDCALL;
6290 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6291 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6292 * Texture and Blitting code to draw the cursor
6294 pSur->Flags |= SFLAG_FORCELOAD;
6295 IWineD3DSurface_PreLoad(pCursorBitmap);
6296 pSur->Flags &= ~SFLAG_FORCELOAD;
6297 /* Do not store the surface's pointer because the application may release
6298 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6299 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6301 This->cursorTexture = pSur->glDescription.textureName;
6302 This->cursorWidth = pSur->currentDesc.Width;
6303 This->cursorHeight = pSur->currentDesc.Height;
6304 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6307 This->xHotSpot = XHotSpot;
6308 This->yHotSpot = YHotSpot;
6309 return WINED3D_OK;
6312 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6314 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6316 This->xScreenSpace = XScreenSpace;
6317 This->yScreenSpace = YScreenSpace;
6319 return;
6323 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6325 BOOL oldVisible = This->bCursorVisible;
6326 TRACE("(%p) : visible(%d)\n", This, bShow);
6328 if(This->cursorTexture)
6329 This->bCursorVisible = bShow;
6331 return oldVisible;
6334 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6336 TRACE("(%p) : state (%u)\n", This, This->state);
6337 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6338 switch (This->state) {
6339 case WINED3D_OK:
6340 return WINED3D_OK;
6341 case WINED3DERR_DEVICELOST:
6343 ResourceList *resourceList = This->resources;
6344 while (NULL != resourceList) {
6345 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6346 return WINED3DERR_DEVICENOTRESET;
6347 resourceList = resourceList->next;
6349 return WINED3DERR_DEVICELOST;
6351 case WINED3DERR_DRIVERINTERNALERROR:
6352 return WINED3DERR_DRIVERINTERNALERROR;
6355 /* Unknown state */
6356 return WINED3DERR_DRIVERINTERNALERROR;
6360 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6362 /** FIXME: Resource tracking needs to be done,
6363 * The closes we can do to this is set the priorities of all managed textures low
6364 * and then reset them.
6365 ***********************************************************/
6366 FIXME("(%p) : stub\n", This);
6367 return WINED3D_OK;
6370 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6371 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6372 if(surface->Flags & SFLAG_DIBSECTION) {
6373 /* Release the DC */
6374 SelectObject(surface->hDC, surface->dib.holdbitmap);
6375 DeleteDC(surface->hDC);
6376 /* Release the DIB section */
6377 DeleteObject(surface->dib.DIBsection);
6378 surface->dib.bitmap_data = NULL;
6379 surface->resource.allocatedMemory = NULL;
6380 surface->Flags &= ~SFLAG_DIBSECTION;
6382 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6383 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6384 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6385 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6386 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6387 } else {
6388 surface->pow2Width = surface->pow2Height = 1;
6389 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6390 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6392 if(surface->glDescription.textureName) {
6393 ENTER_GL();
6394 glDeleteTextures(1, &surface->glDescription.textureName);
6395 LEAVE_GL();
6396 surface->glDescription.textureName = 0;
6398 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6399 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6400 surface->Flags |= SFLAG_NONPOW2;
6401 } else {
6402 surface->Flags &= ~SFLAG_NONPOW2;
6404 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6405 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6408 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6410 IWineD3DSwapChainImpl *swapchain;
6411 HRESULT hr;
6412 BOOL DisplayModeChanged = FALSE;
6413 WINED3DDISPLAYMODE mode;
6414 TRACE("(%p)\n", This);
6416 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6417 if(FAILED(hr)) {
6418 ERR("Failed to get the first implicit swapchain\n");
6419 return hr;
6422 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6423 * on an existing gl context, so there's no real need for recreation.
6425 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6427 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6429 TRACE("New params:\n");
6430 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6431 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6432 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6433 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6434 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6435 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6436 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6437 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6438 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6439 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6440 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6441 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6442 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6444 /* No special treatment of these parameters. Just store them */
6445 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6446 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6447 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6448 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6450 /* What to do about these? */
6451 if(*pPresentationParameters->BackBufferCount != 0 &&
6452 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6453 ERR("Cannot change the back buffer count yet\n");
6455 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6456 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6457 ERR("Cannot change the back buffer format yet\n");
6459 if(*pPresentationParameters->hDeviceWindow != NULL &&
6460 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6461 ERR("Cannot change the device window yet\n");
6463 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6464 ERR("What do do about a changed auto depth stencil parameter?\n");
6467 if(*pPresentationParameters->Windowed) {
6468 mode.Width = swapchain->orig_width;
6469 mode.Height = swapchain->orig_height;
6470 mode.RefreshRate = 0;
6471 mode.Format = swapchain->presentParms.BackBufferFormat;
6472 } else {
6473 mode.Width = *pPresentationParameters->BackBufferWidth;
6474 mode.Height = *pPresentationParameters->BackBufferHeight;
6475 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6476 mode.Format = swapchain->presentParms.BackBufferFormat;
6479 /* Should Width == 800 && Height == 0 set 800x600? */
6480 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6481 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6482 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6484 WINED3DVIEWPORT vp;
6485 int i;
6487 vp.X = 0;
6488 vp.Y = 0;
6489 vp.Width = *pPresentationParameters->BackBufferWidth;
6490 vp.Height = *pPresentationParameters->BackBufferHeight;
6491 vp.MinZ = 0;
6492 vp.MaxZ = 1;
6494 if(!*pPresentationParameters->Windowed) {
6495 DisplayModeChanged = TRUE;
6497 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6498 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6500 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6501 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6502 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6505 /* Now set the new viewport */
6506 IWineD3DDevice_SetViewport(iface, &vp);
6509 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6510 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6511 DisplayModeChanged) {
6512 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6515 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6516 return WINED3D_OK;
6519 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6521 /** FIXME: always true at the moment **/
6522 if(!bEnableDialogs) {
6523 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6525 return WINED3D_OK;
6529 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6531 TRACE("(%p) : pParameters %p\n", This, pParameters);
6533 *pParameters = This->createParms;
6534 return WINED3D_OK;
6537 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6538 IWineD3DSwapChain *swapchain;
6539 HRESULT hrc = WINED3D_OK;
6541 TRACE("Relaying to swapchain\n");
6543 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6544 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6545 IWineD3DSwapChain_Release(swapchain);
6547 return;
6550 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6551 IWineD3DSwapChain *swapchain;
6552 HRESULT hrc = WINED3D_OK;
6554 TRACE("Relaying to swapchain\n");
6556 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6557 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6558 IWineD3DSwapChain_Release(swapchain);
6560 return;
6564 /** ********************************************************
6565 * Notification functions
6566 ** ********************************************************/
6567 /** This function must be called in the release of a resource when ref == 0,
6568 * the contents of resource must still be correct,
6569 * any handels to other resource held by the caller must be closed
6570 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6571 *****************************************************/
6572 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6574 ResourceList* resourceList;
6576 TRACE("(%p) : resource %p\n", This, resource);
6577 #if 0
6578 EnterCriticalSection(&resourceStoreCriticalSection);
6579 #endif
6580 /* add a new texture to the frot of the linked list */
6581 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6582 resourceList->resource = resource;
6584 /* Get the old head */
6585 resourceList->next = This->resources;
6587 This->resources = resourceList;
6588 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6590 #if 0
6591 LeaveCriticalSection(&resourceStoreCriticalSection);
6592 #endif
6593 return;
6596 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6598 ResourceList* resourceList = NULL;
6599 ResourceList* previousResourceList = NULL;
6601 TRACE("(%p) : resource %p\n", This, resource);
6603 #if 0
6604 EnterCriticalSection(&resourceStoreCriticalSection);
6605 #endif
6606 resourceList = This->resources;
6608 while (resourceList != NULL) {
6609 if(resourceList->resource == resource) break;
6610 previousResourceList = resourceList;
6611 resourceList = resourceList->next;
6614 if (resourceList == NULL) {
6615 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6616 #if 0
6617 LeaveCriticalSection(&resourceStoreCriticalSection);
6618 #endif
6619 return;
6620 } else {
6621 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6623 /* make sure we don't leave a hole in the list */
6624 if (previousResourceList != NULL) {
6625 previousResourceList->next = resourceList->next;
6626 } else {
6627 This->resources = resourceList->next;
6630 #if 0
6631 LeaveCriticalSection(&resourceStoreCriticalSection);
6632 #endif
6633 return;
6637 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6639 int counter;
6641 TRACE("(%p) : resource %p\n", This, resource);
6642 switch(IWineD3DResource_GetType(resource)){
6643 case WINED3DRTYPE_SURFACE:
6644 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6645 break;
6646 case WINED3DRTYPE_TEXTURE:
6647 case WINED3DRTYPE_CUBETEXTURE:
6648 case WINED3DRTYPE_VOLUMETEXTURE:
6649 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6650 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6651 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6652 This->stateBlock->textures[counter] = NULL;
6654 if (This->updateStateBlock != This->stateBlock ){
6655 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6656 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6657 This->updateStateBlock->textures[counter] = NULL;
6661 break;
6662 case WINED3DRTYPE_VOLUME:
6663 /* TODO: nothing really? */
6664 break;
6665 case WINED3DRTYPE_VERTEXBUFFER:
6666 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6668 int streamNumber;
6669 TRACE("Cleaning up stream pointers\n");
6671 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6672 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6673 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6675 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6676 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6677 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6678 This->updateStateBlock->streamSource[streamNumber] = 0;
6679 /* Set changed flag? */
6682 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) */
6683 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6684 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6685 This->stateBlock->streamSource[streamNumber] = 0;
6688 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6689 else { /* This shouldn't happen */
6690 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6692 #endif
6696 break;
6697 case WINED3DRTYPE_INDEXBUFFER:
6698 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6699 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6700 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6701 This->updateStateBlock->pIndexData = NULL;
6704 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6705 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6706 This->stateBlock->pIndexData = NULL;
6710 break;
6711 default:
6712 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6713 break;
6717 /* Remove the resoruce from the resourceStore */
6718 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6720 TRACE("Resource released\n");
6724 /**********************************************************
6725 * IWineD3DDevice VTbl follows
6726 **********************************************************/
6728 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6730 /*** IUnknown methods ***/
6731 IWineD3DDeviceImpl_QueryInterface,
6732 IWineD3DDeviceImpl_AddRef,
6733 IWineD3DDeviceImpl_Release,
6734 /*** IWineD3DDevice methods ***/
6735 IWineD3DDeviceImpl_GetParent,
6736 /*** Creation methods**/
6737 IWineD3DDeviceImpl_CreateVertexBuffer,
6738 IWineD3DDeviceImpl_CreateIndexBuffer,
6739 IWineD3DDeviceImpl_CreateStateBlock,
6740 IWineD3DDeviceImpl_CreateSurface,
6741 IWineD3DDeviceImpl_CreateTexture,
6742 IWineD3DDeviceImpl_CreateVolumeTexture,
6743 IWineD3DDeviceImpl_CreateVolume,
6744 IWineD3DDeviceImpl_CreateCubeTexture,
6745 IWineD3DDeviceImpl_CreateQuery,
6746 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6747 IWineD3DDeviceImpl_CreateVertexDeclaration,
6748 IWineD3DDeviceImpl_CreateVertexShader,
6749 IWineD3DDeviceImpl_CreatePixelShader,
6750 IWineD3DDeviceImpl_CreatePalette,
6751 /*** Odd functions **/
6752 IWineD3DDeviceImpl_Init3D,
6753 IWineD3DDeviceImpl_Uninit3D,
6754 IWineD3DDeviceImpl_SetFullscreen,
6755 IWineD3DDeviceImpl_EnumDisplayModes,
6756 IWineD3DDeviceImpl_EvictManagedResources,
6757 IWineD3DDeviceImpl_GetAvailableTextureMem,
6758 IWineD3DDeviceImpl_GetBackBuffer,
6759 IWineD3DDeviceImpl_GetCreationParameters,
6760 IWineD3DDeviceImpl_GetDeviceCaps,
6761 IWineD3DDeviceImpl_GetDirect3D,
6762 IWineD3DDeviceImpl_GetDisplayMode,
6763 IWineD3DDeviceImpl_SetDisplayMode,
6764 IWineD3DDeviceImpl_GetHWND,
6765 IWineD3DDeviceImpl_SetHWND,
6766 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6767 IWineD3DDeviceImpl_GetRasterStatus,
6768 IWineD3DDeviceImpl_GetSwapChain,
6769 IWineD3DDeviceImpl_Reset,
6770 IWineD3DDeviceImpl_SetDialogBoxMode,
6771 IWineD3DDeviceImpl_SetCursorProperties,
6772 IWineD3DDeviceImpl_SetCursorPosition,
6773 IWineD3DDeviceImpl_ShowCursor,
6774 IWineD3DDeviceImpl_TestCooperativeLevel,
6775 /*** Getters and setters **/
6776 IWineD3DDeviceImpl_SetClipPlane,
6777 IWineD3DDeviceImpl_GetClipPlane,
6778 IWineD3DDeviceImpl_SetClipStatus,
6779 IWineD3DDeviceImpl_GetClipStatus,
6780 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6781 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6782 IWineD3DDeviceImpl_SetDepthStencilSurface,
6783 IWineD3DDeviceImpl_GetDepthStencilSurface,
6784 IWineD3DDeviceImpl_SetFVF,
6785 IWineD3DDeviceImpl_GetFVF,
6786 IWineD3DDeviceImpl_SetGammaRamp,
6787 IWineD3DDeviceImpl_GetGammaRamp,
6788 IWineD3DDeviceImpl_SetIndices,
6789 IWineD3DDeviceImpl_GetIndices,
6790 IWineD3DDeviceImpl_SetLight,
6791 IWineD3DDeviceImpl_GetLight,
6792 IWineD3DDeviceImpl_SetLightEnable,
6793 IWineD3DDeviceImpl_GetLightEnable,
6794 IWineD3DDeviceImpl_SetMaterial,
6795 IWineD3DDeviceImpl_GetMaterial,
6796 IWineD3DDeviceImpl_SetNPatchMode,
6797 IWineD3DDeviceImpl_GetNPatchMode,
6798 IWineD3DDeviceImpl_SetPaletteEntries,
6799 IWineD3DDeviceImpl_GetPaletteEntries,
6800 IWineD3DDeviceImpl_SetPixelShader,
6801 IWineD3DDeviceImpl_GetPixelShader,
6802 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6803 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6804 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6805 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6806 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6807 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6808 IWineD3DDeviceImpl_SetRenderState,
6809 IWineD3DDeviceImpl_GetRenderState,
6810 IWineD3DDeviceImpl_SetRenderTarget,
6811 IWineD3DDeviceImpl_GetRenderTarget,
6812 IWineD3DDeviceImpl_SetFrontBackBuffers,
6813 IWineD3DDeviceImpl_SetSamplerState,
6814 IWineD3DDeviceImpl_GetSamplerState,
6815 IWineD3DDeviceImpl_SetScissorRect,
6816 IWineD3DDeviceImpl_GetScissorRect,
6817 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6818 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6819 IWineD3DDeviceImpl_SetStreamSource,
6820 IWineD3DDeviceImpl_GetStreamSource,
6821 IWineD3DDeviceImpl_SetStreamSourceFreq,
6822 IWineD3DDeviceImpl_GetStreamSourceFreq,
6823 IWineD3DDeviceImpl_SetTexture,
6824 IWineD3DDeviceImpl_GetTexture,
6825 IWineD3DDeviceImpl_SetTextureStageState,
6826 IWineD3DDeviceImpl_GetTextureStageState,
6827 IWineD3DDeviceImpl_SetTransform,
6828 IWineD3DDeviceImpl_GetTransform,
6829 IWineD3DDeviceImpl_SetVertexDeclaration,
6830 IWineD3DDeviceImpl_GetVertexDeclaration,
6831 IWineD3DDeviceImpl_SetVertexShader,
6832 IWineD3DDeviceImpl_GetVertexShader,
6833 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6834 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6835 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6836 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6837 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6838 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6839 IWineD3DDeviceImpl_SetViewport,
6840 IWineD3DDeviceImpl_GetViewport,
6841 IWineD3DDeviceImpl_MultiplyTransform,
6842 IWineD3DDeviceImpl_ValidateDevice,
6843 IWineD3DDeviceImpl_ProcessVertices,
6844 /*** State block ***/
6845 IWineD3DDeviceImpl_BeginStateBlock,
6846 IWineD3DDeviceImpl_EndStateBlock,
6847 /*** Scene management ***/
6848 IWineD3DDeviceImpl_BeginScene,
6849 IWineD3DDeviceImpl_EndScene,
6850 IWineD3DDeviceImpl_Present,
6851 IWineD3DDeviceImpl_Clear,
6852 /*** Drawing ***/
6853 IWineD3DDeviceImpl_DrawPrimitive,
6854 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6855 IWineD3DDeviceImpl_DrawPrimitiveUP,
6856 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6857 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6858 IWineD3DDeviceImpl_DrawRectPatch,
6859 IWineD3DDeviceImpl_DrawTriPatch,
6860 IWineD3DDeviceImpl_DeletePatch,
6861 IWineD3DDeviceImpl_ColorFill,
6862 IWineD3DDeviceImpl_UpdateTexture,
6863 IWineD3DDeviceImpl_UpdateSurface,
6864 IWineD3DDeviceImpl_StretchRect,
6865 IWineD3DDeviceImpl_GetRenderTargetData,
6866 IWineD3DDeviceImpl_GetFrontBufferData,
6867 /*** Internal use IWineD3DDevice methods ***/
6868 IWineD3DDeviceImpl_SetupTextureStates,
6869 /*** object tracking ***/
6870 IWineD3DDeviceImpl_ResourceReleased
6874 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6875 WINED3DRS_ALPHABLENDENABLE ,
6876 WINED3DRS_ALPHAFUNC ,
6877 WINED3DRS_ALPHAREF ,
6878 WINED3DRS_ALPHATESTENABLE ,
6879 WINED3DRS_BLENDOP ,
6880 WINED3DRS_COLORWRITEENABLE ,
6881 WINED3DRS_DESTBLEND ,
6882 WINED3DRS_DITHERENABLE ,
6883 WINED3DRS_FILLMODE ,
6884 WINED3DRS_FOGDENSITY ,
6885 WINED3DRS_FOGEND ,
6886 WINED3DRS_FOGSTART ,
6887 WINED3DRS_LASTPIXEL ,
6888 WINED3DRS_SHADEMODE ,
6889 WINED3DRS_SRCBLEND ,
6890 WINED3DRS_STENCILENABLE ,
6891 WINED3DRS_STENCILFAIL ,
6892 WINED3DRS_STENCILFUNC ,
6893 WINED3DRS_STENCILMASK ,
6894 WINED3DRS_STENCILPASS ,
6895 WINED3DRS_STENCILREF ,
6896 WINED3DRS_STENCILWRITEMASK ,
6897 WINED3DRS_STENCILZFAIL ,
6898 WINED3DRS_TEXTUREFACTOR ,
6899 WINED3DRS_WRAP0 ,
6900 WINED3DRS_WRAP1 ,
6901 WINED3DRS_WRAP2 ,
6902 WINED3DRS_WRAP3 ,
6903 WINED3DRS_WRAP4 ,
6904 WINED3DRS_WRAP5 ,
6905 WINED3DRS_WRAP6 ,
6906 WINED3DRS_WRAP7 ,
6907 WINED3DRS_ZENABLE ,
6908 WINED3DRS_ZFUNC ,
6909 WINED3DRS_ZWRITEENABLE
6912 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6913 WINED3DTSS_ADDRESSW ,
6914 WINED3DTSS_ALPHAARG0 ,
6915 WINED3DTSS_ALPHAARG1 ,
6916 WINED3DTSS_ALPHAARG2 ,
6917 WINED3DTSS_ALPHAOP ,
6918 WINED3DTSS_BUMPENVLOFFSET ,
6919 WINED3DTSS_BUMPENVLSCALE ,
6920 WINED3DTSS_BUMPENVMAT00 ,
6921 WINED3DTSS_BUMPENVMAT01 ,
6922 WINED3DTSS_BUMPENVMAT10 ,
6923 WINED3DTSS_BUMPENVMAT11 ,
6924 WINED3DTSS_COLORARG0 ,
6925 WINED3DTSS_COLORARG1 ,
6926 WINED3DTSS_COLORARG2 ,
6927 WINED3DTSS_COLOROP ,
6928 WINED3DTSS_RESULTARG ,
6929 WINED3DTSS_TEXCOORDINDEX ,
6930 WINED3DTSS_TEXTURETRANSFORMFLAGS
6933 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6934 WINED3DSAMP_ADDRESSU ,
6935 WINED3DSAMP_ADDRESSV ,
6936 WINED3DSAMP_ADDRESSW ,
6937 WINED3DSAMP_BORDERCOLOR ,
6938 WINED3DSAMP_MAGFILTER ,
6939 WINED3DSAMP_MINFILTER ,
6940 WINED3DSAMP_MIPFILTER ,
6941 WINED3DSAMP_MIPMAPLODBIAS ,
6942 WINED3DSAMP_MAXMIPLEVEL ,
6943 WINED3DSAMP_MAXANISOTROPY ,
6944 WINED3DSAMP_SRGBTEXTURE ,
6945 WINED3DSAMP_ELEMENTINDEX
6948 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6949 WINED3DRS_AMBIENT ,
6950 WINED3DRS_AMBIENTMATERIALSOURCE ,
6951 WINED3DRS_CLIPPING ,
6952 WINED3DRS_CLIPPLANEENABLE ,
6953 WINED3DRS_COLORVERTEX ,
6954 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6955 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6956 WINED3DRS_FOGDENSITY ,
6957 WINED3DRS_FOGEND ,
6958 WINED3DRS_FOGSTART ,
6959 WINED3DRS_FOGTABLEMODE ,
6960 WINED3DRS_FOGVERTEXMODE ,
6961 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6962 WINED3DRS_LIGHTING ,
6963 WINED3DRS_LOCALVIEWER ,
6964 WINED3DRS_MULTISAMPLEANTIALIAS ,
6965 WINED3DRS_MULTISAMPLEMASK ,
6966 WINED3DRS_NORMALIZENORMALS ,
6967 WINED3DRS_PATCHEDGESTYLE ,
6968 WINED3DRS_POINTSCALE_A ,
6969 WINED3DRS_POINTSCALE_B ,
6970 WINED3DRS_POINTSCALE_C ,
6971 WINED3DRS_POINTSCALEENABLE ,
6972 WINED3DRS_POINTSIZE ,
6973 WINED3DRS_POINTSIZE_MAX ,
6974 WINED3DRS_POINTSIZE_MIN ,
6975 WINED3DRS_POINTSPRITEENABLE ,
6976 WINED3DRS_RANGEFOGENABLE ,
6977 WINED3DRS_SPECULARMATERIALSOURCE ,
6978 WINED3DRS_TWEENFACTOR ,
6979 WINED3DRS_VERTEXBLEND
6982 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6983 WINED3DTSS_TEXCOORDINDEX ,
6984 WINED3DTSS_TEXTURETRANSFORMFLAGS
6987 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6988 WINED3DSAMP_DMAPOFFSET
6991 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6992 DWORD rep = StateTable[state].representative;
6993 DWORD idx;
6994 BYTE shift;
6996 if(!rep || isStateDirty(This, rep)) return;
6998 This->dirtyArray[This->numDirtyEntries++] = rep;
6999 idx = rep >> 5;
7000 shift = rep & 0x1f;
7001 This->isStateDirty[idx] |= (1 << shift);