Revert "wined3d: Where possible, avoid using D3DCOLORTOGLFLOAT4."
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob63f84f843d219440fa2f5d8dca8fd51340e5376a
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 WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
82 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
84 /* helper macros */
85 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
87 #define D3DCREATEOBJECTINSTANCE(object, type) { \
88 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
89 D3DMEMCHECK(object, pp##type); \
90 object->lpVtbl = &IWineD3D##type##_Vtbl; \
91 object->wineD3DDevice = This; \
92 object->parent = parent; \
93 object->ref = 1; \
94 *pp##type = (IWineD3D##type *) object; \
97 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
98 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
99 D3DMEMCHECK(object, pp##type); \
100 object->lpVtbl = &IWineD3D##type##_Vtbl; \
101 object->parent = parent; \
102 object->ref = 1; \
103 object->baseShader.device = (IWineD3DDevice*) This; \
104 *pp##type = (IWineD3D##type *) object; \
107 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
108 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
109 D3DMEMCHECK(object, pp##type); \
110 object->lpVtbl = &IWineD3D##type##_Vtbl; \
111 object->resource.wineD3DDevice = This; \
112 object->resource.parent = parent; \
113 object->resource.resourceType = d3dtype; \
114 object->resource.ref = 1; \
115 object->resource.pool = Pool; \
116 object->resource.format = Format; \
117 object->resource.usage = Usage; \
118 object->resource.size = _size; \
119 /* Check that we have enough video ram left */ \
120 if (Pool == WINED3DPOOL_DEFAULT) { \
121 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
122 WARN("Out of 'bogus' video memory\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 globalChangeGlRam(_size); \
129 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
130 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
131 FIXME("Out of memory!\n"); \
132 HeapFree(GetProcessHeap(), 0, object); \
133 *pp##type = NULL; \
134 return WINED3DERR_OUTOFVIDEOMEMORY; \
136 *pp##type = (IWineD3D##type *) object; \
137 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
138 TRACE("(%p) : Created resource %p\n", This, object); \
141 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
142 _basetexture.levels = Levels; \
143 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
144 _basetexture.LOD = 0; \
145 _basetexture.dirty = TRUE; \
148 /**********************************************************
149 * Global variable / Constants follow
150 **********************************************************/
151 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
153 /**********************************************************
154 * Utility functions follow
155 **********************************************************/
156 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
157 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
159 float quad_att;
160 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
163 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
164 glMatrixMode(GL_MODELVIEW);
165 glPushMatrix();
166 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
168 /* Diffuse: */
169 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
170 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
171 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
172 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
173 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
174 checkGLcall("glLightfv");
176 /* Specular */
177 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
178 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
179 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
180 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
181 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
182 checkGLcall("glLightfv");
184 /* Ambient */
185 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
186 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
187 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
188 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
189 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
190 checkGLcall("glLightfv");
192 /* Attenuation - Are these right? guessing... */
193 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
194 checkGLcall("glLightf");
195 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
196 checkGLcall("glLightf");
198 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
199 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
200 } else {
201 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
204 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
205 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
206 checkGLcall("glLightf");
208 switch (lightInfo->OriginalParms.Type) {
209 case WINED3DLIGHT_POINT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
214 checkGLcall("glLightf");
215 /* FIXME: Range */
216 break;
218 case WINED3DLIGHT_SPOT:
219 /* Position */
220 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
221 checkGLcall("glLightfv");
222 /* Direction */
223 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
224 checkGLcall("glLightfv");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
226 checkGLcall("glLightf");
227 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 /* FIXME: Range */
230 break;
232 case WINED3DLIGHT_DIRECTIONAL:
233 /* Direction */
234 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
235 checkGLcall("glLightfv");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
237 checkGLcall("glLightf");
238 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
239 checkGLcall("glLightf");
240 break;
242 default:
243 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
246 /* Restore the modelview matrix */
247 glPopMatrix();
250 /**********************************************************
251 * GLSL helper functions follow
252 **********************************************************/
254 /** Detach the GLSL pixel or vertex shader object from the shader program */
255 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
259 if (shaderObj != 0 && programId != 0) {
260 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
261 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
262 checkGLcall("glDetachObjectARB");
266 /** Delete a GLSL shader program */
267 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
271 if (obj != 0) {
272 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
273 GL_EXTCALL(glDeleteObjectARB(obj));
274 checkGLcall("glDeleteObjectARB");
278 /** Delete the list of linked programs this shader is associated with.
279 * Also at this point, check to see if there are any objects left attached
280 * to each GLSL program. If not, delete the GLSL program object.
281 * This will be run when a device is released. */
282 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
284 struct list *ptr = NULL;
285 struct glsl_shader_prog_link *curLink = NULL;
286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
288 int numAttached = 0;
289 int i;
290 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
291 (one pixel shader and one vertex shader at most) */
293 ptr = list_head( &This->glsl_shader_progs );
294 while (ptr) {
295 /* First, get the current item,
296 * save the link to the next pointer,
297 * detach and delete shader objects,
298 * then de-allocate the list item's memory */
299 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
300 ptr = list_next( &This->glsl_shader_progs, ptr );
302 /* See if this object is still attached to the program - it may have been detached already */
303 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
304 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
305 for (i = 0; i < numAttached; i++) {
306 detach_glsl_shader(iface, objList[i], curLink->programId);
309 delete_glsl_shader_program(iface, curLink->programId);
311 /* Free the uniform locations */
312 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
313 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
315 /* Free the memory for this list item */
316 HeapFree(GetProcessHeap(), 0, curLink);
321 /* Apply the current values to the specified texture stage */
322 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
324 float col[4];
326 union {
327 float f;
328 DWORD d;
329 } tmpvalue;
331 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
332 clamping, MIPLOD, etc. This will work for up to 16 samplers.
335 if (Sampler >= GL_LIMITS(sampler_stages)) {
336 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
337 return;
339 VTRACE(("Activating appropriate texture state %d\n", Sampler));
340 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
341 ENTER_GL();
342 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
343 checkGLcall("glActiveTextureARB");
344 LEAVE_GL();
345 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
346 } else if (Sampler > 0) {
347 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
348 return;
351 /* TODO: change this to a lookup table
352 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
353 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
354 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
355 especially when there are a number of groups of states. */
357 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
359 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
360 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
361 /* these are the only two supported states that need to be applied */
362 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
363 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
364 #if 0 /* not supported at the moment */
365 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
366 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
367 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
368 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
369 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
370 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
371 APPLY_STATE(WINED3DTSS_RESULTARG);
372 APPLY_STATE(WINED3DTSS_CONSTANT);
373 #endif
374 /* a quick sanity check in case someone forgot to update this function */
375 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
376 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
378 #undef APPLY_STATE
380 /* apply any sampler states that always need applying */
381 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
382 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
383 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
384 GL_TEXTURE_LOD_BIAS_EXT,
385 tmpvalue.f);
386 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
389 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
390 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
391 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
393 /* TODO: NV_POINT_SPRITE */
394 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
395 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
396 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
397 glDisable(GL_POINT_SMOOTH);
399 /* Centre the texture on the vertex */
400 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
401 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
403 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
404 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
405 checkGLcall("glTexEnvf(...)");
406 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
407 glEnable( GL_POINT_SPRITE_ARB );
408 checkGLcall("glEnable(...)");
409 } else {
410 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
411 glDisable( GL_POINT_SPRITE_ARB );
412 checkGLcall("glEnable(...)");
416 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
419 /**********************************************************
420 * IUnknown parts follows
421 **********************************************************/
423 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
427 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
428 if (IsEqualGUID(riid, &IID_IUnknown)
429 || IsEqualGUID(riid, &IID_IWineD3DBase)
430 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
431 IUnknown_AddRef(iface);
432 *ppobj = This;
433 return S_OK;
435 *ppobj = NULL;
436 return E_NOINTERFACE;
439 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 ULONG refCount = InterlockedIncrement(&This->ref);
443 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
444 return refCount;
447 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
449 ULONG refCount = InterlockedDecrement(&This->ref);
451 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
453 if (!refCount) {
454 if (This->fbo) {
455 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
458 HeapFree(GetProcessHeap(), 0, This->render_targets);
460 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
462 /* TODO: Clean up all the surfaces and textures! */
463 /* NOTE: You must release the parent if the object was created via a callback
464 ** ***************************/
466 /* Delete any GLSL shader programs that may exist */
467 if (This->vs_selected_mode == SHADER_GLSL ||
468 This->ps_selected_mode == SHADER_GLSL)
469 delete_glsl_shader_list(iface);
471 /* Release the update stateblock */
472 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
473 if(This->updateStateBlock != This->stateBlock)
474 FIXME("(%p) Something's still holding the Update stateblock\n",This);
476 This->updateStateBlock = NULL;
477 { /* because were not doing proper internal refcounts releasing the primary state block
478 causes recursion with the extra checks in ResourceReleased, to avoid this we have
479 to set this->stateBlock = NULL; first */
480 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
481 This->stateBlock = NULL;
483 /* Release the stateblock */
484 if(IWineD3DStateBlock_Release(stateBlock) > 0){
485 FIXME("(%p) Something's still holding the Update stateblock\n",This);
489 if (This->resources != NULL ) {
490 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
491 dumpResources(This->resources);
495 IWineD3D_Release(This->wineD3D);
496 This->wineD3D = NULL;
497 HeapFree(GetProcessHeap(), 0, This);
498 TRACE("Freed device %p\n", This);
499 This = NULL;
501 return refCount;
504 /**********************************************************
505 * IWineD3DDevice implementation follows
506 **********************************************************/
507 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 *pParent = This->parent;
510 IUnknown_AddRef(This->parent);
511 return WINED3D_OK;
514 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
515 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
516 GLenum error, glUsage;
517 DWORD vboUsage = object->resource.usage;
518 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
519 WARN("Creating a vbo failed once, not trying again\n");
520 return;
523 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
525 ENTER_GL();
526 /* Make sure that the gl error is cleared. Do not use checkGLcall
527 * here because checkGLcall just prints a fixme and continues. However,
528 * if an error during VBO creation occurs we can fall back to non-vbo operation
529 * with full functionality(but performance loss)
531 while(glGetError() != GL_NO_ERROR);
533 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
534 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
535 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
536 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
537 * to check if the rhw and color values are in the correct format.
540 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
541 error = glGetError();
542 if(object->vbo == 0 || error != GL_NO_ERROR) {
543 WARN("Failed to create a VBO with error %d\n", error);
544 goto error;
547 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
548 error = glGetError();
549 if(error != GL_NO_ERROR) {
550 WARN("Failed to bind the VBO, error %d\n", error);
551 goto error;
554 /* Transformed vertices are horribly inflexible. If the app specifies an
555 * vertex buffer with transformed vertices in default pool without DYNAMIC
556 * usage assume DYNAMIC usage and print a warning. The app will have to update
557 * the vertices regularily for them to be useful
559 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
560 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
561 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
562 vboUsage |= WINED3DUSAGE_DYNAMIC;
565 /* Don't use static, because dx apps tend to update the buffer
566 * quite often even if they specify 0 usage
568 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
569 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
570 TRACE("Gl usage = GL_STREAM_DRAW\n");
571 glUsage = GL_STREAM_DRAW_ARB;
572 break;
573 case D3DUSAGE_WRITEONLY:
574 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
575 glUsage = GL_DYNAMIC_DRAW_ARB;
576 break;
577 case D3DUSAGE_DYNAMIC:
578 TRACE("Gl usage = GL_STREAM_COPY\n");
579 glUsage = GL_STREAM_COPY_ARB;
580 break;
581 default:
582 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
583 glUsage = GL_DYNAMIC_COPY_ARB;
584 break;
587 /* Reserve memory for the buffer. The amount of data won't change
588 * so we are safe with calling glBufferData once with a NULL ptr and
589 * calling glBufferSubData on updates
591 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
592 error = glGetError();
593 if(error != GL_NO_ERROR) {
594 WARN("glBufferDataARB failed with error %d\n", error);
595 goto error;
598 LEAVE_GL();
600 return;
601 error:
602 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
603 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
604 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
605 object->vbo = 0;
606 object->Flags |= VBFLAG_VBOCREATEFAIL;
607 LEAVE_GL();
608 return;
611 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
612 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
613 IUnknown *parent) {
614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
615 IWineD3DVertexBufferImpl *object;
616 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
617 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
618 BOOL conv;
619 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
621 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
622 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
624 if(Size == 0) return WINED3DERR_INVALIDCALL;
626 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
627 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
629 object->fvf = FVF;
631 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
632 * drawStridedFast (half-life 2).
634 * Basically converting the vertices in the buffer is quite expensive, and observations
635 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
636 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
638 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
639 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
640 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
641 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
642 * dx7 apps.
643 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
644 * more. In this call we can convert dx7 buffers too.
646 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
647 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
648 (dxVersion > 7 || !conv) ) {
649 CreateVBO(object);
651 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
652 if(dxVersion == 7 && object->vbo) {
653 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
654 object->resource.allocatedMemory = NULL;
658 return WINED3D_OK;
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
662 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
663 HANDLE *sharedHandle, IUnknown *parent) {
664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
665 IWineD3DIndexBufferImpl *object;
666 TRACE("(%p) Creating index buffer\n", This);
668 /* Allocate the storage for the device */
669 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
671 /*TODO: use VBO's */
672 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
673 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
676 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
677 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
678 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
680 return WINED3D_OK;
683 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
686 IWineD3DStateBlockImpl *object;
687 int i, j;
688 HRESULT temp_result;
690 D3DCREATEOBJECTINSTANCE(object, StateBlock)
691 object->blockType = Type;
693 /* Special case - Used during initialization to produce a placeholder stateblock
694 so other functions called can update a state block */
695 if (Type == WINED3DSBT_INIT) {
696 /* Don't bother increasing the reference count otherwise a device will never
697 be freed due to circular dependencies */
698 return WINED3D_OK;
701 temp_result = allocate_shader_constants(object);
702 if (WINED3D_OK != temp_result)
703 return temp_result;
705 /* Otherwise, might as well set the whole state block to the appropriate values */
706 if (This->stateBlock != NULL)
707 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
708 else
709 memset(object->streamFreq, 1, sizeof(object->streamFreq));
711 /* Reset the ref and type after kludging it */
712 object->wineD3DDevice = This;
713 object->ref = 1;
714 object->blockType = Type;
716 TRACE("Updating changed flags appropriate for type %d\n", Type);
718 if (Type == WINED3DSBT_ALL) {
720 TRACE("ALL => Pretend everything has changed\n");
721 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
723 } else if (Type == WINED3DSBT_PIXELSTATE) {
725 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
726 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
728 object->changed.pixelShader = TRUE;
730 /* Pixel Shader Constants */
731 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
732 object->changed.pixelShaderConstantsF[i] = TRUE;
733 for (i = 0; i < MAX_CONST_B; ++i)
734 object->changed.pixelShaderConstantsB[i] = TRUE;
735 for (i = 0; i < MAX_CONST_I; ++i)
736 object->changed.pixelShaderConstantsI[i] = TRUE;
738 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
739 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
741 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
742 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
743 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
746 for (j = 0 ; j < 16; j++) {
747 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
749 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
753 } else if (Type == WINED3DSBT_VERTEXSTATE) {
755 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
756 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
758 object->changed.vertexShader = TRUE;
760 /* Vertex Shader Constants */
761 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
762 object->changed.vertexShaderConstantsF[i] = TRUE;
763 for (i = 0; i < MAX_CONST_B; ++i)
764 object->changed.vertexShaderConstantsB[i] = TRUE;
765 for (i = 0; i < MAX_CONST_I; ++i)
766 object->changed.vertexShaderConstantsI[i] = TRUE;
768 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
769 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
771 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
772 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
773 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
776 for (j = 0 ; j < 16; j++){
777 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
778 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
782 /* Duplicate light chain */
784 PLIGHTINFOEL *src = NULL;
785 PLIGHTINFOEL *dst = NULL;
786 PLIGHTINFOEL *newEl = NULL;
787 src = This->stateBlock->lights;
788 object->lights = NULL;
791 while (src) {
792 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
793 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
794 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
795 newEl->prev = dst;
796 newEl->changed = TRUE;
797 newEl->enabledChanged = TRUE;
798 if (dst == NULL) {
799 object->lights = newEl;
800 } else {
801 dst->next = newEl;
803 dst = newEl;
804 src = src->next;
809 } else {
810 FIXME("Unrecognized state block type %d\n", Type);
813 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
814 return WINED3D_OK;
818 /* ************************************
819 MSDN:
820 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
822 Discard
823 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
825 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.
827 ******************************** */
829 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) {
830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
831 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
832 unsigned int pow2Width, pow2Height;
833 unsigned int Size = 1;
834 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
835 TRACE("(%p) Create surface\n",This);
837 /** FIXME: Check ranges on the inputs are valid
838 * MSDN
839 * MultisampleQuality
840 * [in] Quality level. The valid range is between zero and one less than the level
841 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
842 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
843 * values of paired render targets, depth stencil surfaces, and the MultiSample type
844 * must all match.
845 *******************************/
849 * TODO: Discard MSDN
850 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
852 * If this flag is set, the contents of the depth stencil buffer will be
853 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
854 * with a different depth surface.
856 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
857 ***************************/
859 if(MultisampleQuality < 0) {
860 FIXME("Invalid multisample level %d\n", MultisampleQuality);
861 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
864 if(MultisampleQuality > 0) {
865 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
866 MultisampleQuality=0;
869 /** FIXME: Check that the format is supported
870 * by the device.
871 *******************************/
873 /* Non-power2 support */
874 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
875 pow2Width = Width;
876 pow2Height = Height;
877 } else {
878 /* Find the nearest pow2 match */
879 pow2Width = pow2Height = 1;
880 while (pow2Width < Width) pow2Width <<= 1;
881 while (pow2Height < Height) pow2Height <<= 1;
884 if (pow2Width > Width || pow2Height > Height) {
885 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
886 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
887 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
888 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
889 This, Width, Height);
890 return WINED3DERR_NOTAVAILABLE;
894 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
895 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
896 * space!
897 *********************************/
898 if (WINED3DFMT_UNKNOWN == Format) {
899 Size = 0;
900 } else if (Format == WINED3DFMT_DXT1) {
901 /* DXT1 is half byte per pixel */
902 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
904 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
905 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
906 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
907 } else {
908 /* The pitch is a multiple of 4 bytes */
909 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
910 Size *= pow2Height;
913 /** Create and initialise the surface resource **/
914 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
915 /* "Standalone" surface */
916 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
918 object->currentDesc.Width = Width;
919 object->currentDesc.Height = Height;
920 object->currentDesc.MultiSampleType = MultiSample;
921 object->currentDesc.MultiSampleQuality = MultisampleQuality;
923 /* Setup some glformat defaults */
924 object->glDescription.glFormat = tableEntry->glFormat;
925 object->glDescription.glFormatInternal = tableEntry->glInternal;
926 object->glDescription.glType = tableEntry->glType;
928 object->glDescription.textureName = 0;
929 object->glDescription.level = Level;
930 object->glDescription.target = GL_TEXTURE_2D;
932 /* Internal data */
933 object->pow2Width = pow2Width;
934 object->pow2Height = pow2Height;
936 /* Flags */
937 object->Flags = 0; /* We start without flags set */
938 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
939 object->Flags |= Discard ? SFLAG_DISCARD : 0;
940 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
941 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
944 if (WINED3DFMT_UNKNOWN != Format) {
945 object->bytesPerPixel = tableEntry->bpp;
946 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
947 object->pow2Size *= pow2Height;
948 } else {
949 object->bytesPerPixel = 0;
950 object->pow2Size = 0;
953 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
955 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
957 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
958 * this function is too deep to need to care about things like this.
959 * Levels need to be checked too, and possibly Type since they all affect what can be done.
960 * ****************************************/
961 switch(Pool) {
962 case WINED3DPOOL_SCRATCH:
963 if(!Lockable)
964 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
965 which are mutually exclusive, setting lockable to true\n");
966 Lockable = TRUE;
967 break;
968 case WINED3DPOOL_SYSTEMMEM:
969 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
970 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
971 case WINED3DPOOL_MANAGED:
972 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
973 Usage of DYNAMIC which are mutually exclusive, not doing \
974 anything just telling you.\n");
975 break;
976 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
977 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
978 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
979 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
980 break;
981 default:
982 FIXME("(%p) Unknown pool %d\n", This, Pool);
983 break;
986 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
987 FIXME("Trying to create a render target that isn't in the default pool\n");
990 /* mark the texture as dirty so that it gets loaded first time around*/
991 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
992 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
993 This, Width, Height, Format, debug_d3dformat(Format),
994 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
996 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
997 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
998 This->ddraw_primary = (IWineD3DSurface *) object;
1000 /* Look at the implementation and set the correct Vtable */
1001 switch(Impl) {
1002 case SURFACE_OPENGL:
1003 /* Nothing to do, it's set already */
1004 break;
1006 case SURFACE_GDI:
1007 object->lpVtbl = &IWineGDISurface_Vtbl;
1008 break;
1010 default:
1011 /* To be sure to catch this */
1012 ERR("Unknown requested surface implementation %d!\n", Impl);
1013 IWineD3DSurface_Release((IWineD3DSurface *) object);
1014 return WINED3DERR_INVALIDCALL;
1017 /* Call the private setup routine */
1018 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1022 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1023 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1024 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1025 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1028 IWineD3DTextureImpl *object;
1029 unsigned int i;
1030 UINT tmpW;
1031 UINT tmpH;
1032 HRESULT hr;
1033 unsigned int pow2Width;
1034 unsigned int pow2Height;
1037 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1038 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1039 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1041 /* TODO: It should only be possible to create textures for formats
1042 that are reported as supported */
1043 if (WINED3DFMT_UNKNOWN >= Format) {
1044 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1045 return WINED3DERR_INVALIDCALL;
1048 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1049 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1050 object->width = Width;
1051 object->height = Height;
1053 /** Non-power2 support **/
1054 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1055 pow2Width = Width;
1056 pow2Height = Height;
1057 } else {
1058 /* Find the nearest pow2 match */
1059 pow2Width = pow2Height = 1;
1060 while (pow2Width < Width) pow2Width <<= 1;
1061 while (pow2Height < Height) pow2Height <<= 1;
1064 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1065 /* Precalculated scaling for 'faked' non power of two texture coords */
1066 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1067 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1068 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1070 /* Calculate levels for mip mapping */
1071 if (Levels == 0) {
1072 TRACE("calculating levels %d\n", object->baseTexture.levels);
1073 object->baseTexture.levels++;
1074 tmpW = Width;
1075 tmpH = Height;
1076 while (tmpW > 1 || tmpH > 1) {
1077 tmpW = max(1, tmpW >> 1);
1078 tmpH = max(1, tmpH >> 1);
1079 object->baseTexture.levels++;
1081 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1084 /* Generate all the surfaces */
1085 tmpW = Width;
1086 tmpH = Height;
1087 for (i = 0; i < object->baseTexture.levels; i++)
1089 /* use the callback to create the texture surface */
1090 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1091 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1092 FIXME("Failed to create surface %p\n", object);
1093 /* clean up */
1094 object->surfaces[i] = NULL;
1095 IWineD3DTexture_Release((IWineD3DTexture *)object);
1097 *ppTexture = NULL;
1098 return hr;
1101 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1102 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1103 /* calculate the next mipmap level */
1104 tmpW = max(1, tmpW >> 1);
1105 tmpH = max(1, tmpH >> 1);
1108 TRACE("(%p) : Created texture %p\n", This, object);
1109 return WINED3D_OK;
1112 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1113 UINT Width, UINT Height, UINT Depth,
1114 UINT Levels, DWORD Usage,
1115 WINED3DFORMAT Format, WINED3DPOOL Pool,
1116 IWineD3DVolumeTexture **ppVolumeTexture,
1117 HANDLE *pSharedHandle, IUnknown *parent,
1118 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1121 IWineD3DVolumeTextureImpl *object;
1122 unsigned int i;
1123 UINT tmpW;
1124 UINT tmpH;
1125 UINT tmpD;
1127 /* TODO: It should only be possible to create textures for formats
1128 that are reported as supported */
1129 if (WINED3DFMT_UNKNOWN >= Format) {
1130 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1131 return WINED3DERR_INVALIDCALL;
1134 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1135 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1138 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1140 object->width = Width;
1141 object->height = Height;
1142 object->depth = Depth;
1144 /* Calculate levels for mip mapping */
1145 if (Levels == 0) {
1146 object->baseTexture.levels++;
1147 tmpW = Width;
1148 tmpH = Height;
1149 tmpD = Depth;
1150 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1151 tmpW = max(1, tmpW >> 1);
1152 tmpH = max(1, tmpH >> 1);
1153 tmpD = max(1, tmpD >> 1);
1154 object->baseTexture.levels++;
1156 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1159 /* Generate all the surfaces */
1160 tmpW = Width;
1161 tmpH = Height;
1162 tmpD = Depth;
1164 for (i = 0; i < object->baseTexture.levels; i++)
1166 /* Create the volume */
1167 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1168 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1170 /* Set its container to this object */
1171 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1173 /* calcualte the next mipmap level */
1174 tmpW = max(1, tmpW >> 1);
1175 tmpH = max(1, tmpH >> 1);
1176 tmpD = max(1, tmpD >> 1);
1179 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1180 TRACE("(%p) : Created volume texture %p\n", This, object);
1181 return WINED3D_OK;
1184 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1185 UINT Width, UINT Height, UINT Depth,
1186 DWORD Usage,
1187 WINED3DFORMAT Format, WINED3DPOOL Pool,
1188 IWineD3DVolume** ppVolume,
1189 HANDLE* pSharedHandle, IUnknown *parent) {
1191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1192 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1193 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1195 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1197 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1198 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1200 object->currentDesc.Width = Width;
1201 object->currentDesc.Height = Height;
1202 object->currentDesc.Depth = Depth;
1203 object->bytesPerPixel = formatDesc->bpp;
1205 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1206 object->lockable = TRUE;
1207 object->locked = FALSE;
1208 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1209 object->dirty = TRUE;
1211 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1214 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1215 UINT Levels, DWORD Usage,
1216 WINED3DFORMAT Format, WINED3DPOOL Pool,
1217 IWineD3DCubeTexture **ppCubeTexture,
1218 HANDLE *pSharedHandle, IUnknown *parent,
1219 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1223 unsigned int i, j;
1224 UINT tmpW;
1225 HRESULT hr;
1226 unsigned int pow2EdgeLength = EdgeLength;
1228 /* TODO: It should only be possible to create textures for formats
1229 that are reported as supported */
1230 if (WINED3DFMT_UNKNOWN >= Format) {
1231 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1232 return WINED3DERR_INVALIDCALL;
1235 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1236 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1238 TRACE("(%p) Create Cube Texture\n", This);
1240 /** Non-power2 support **/
1242 /* Find the nearest pow2 match */
1243 pow2EdgeLength = 1;
1244 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1246 object->edgeLength = EdgeLength;
1247 /* TODO: support for native non-power 2 */
1248 /* Precalculated scaling for 'faked' non power of two texture coords */
1249 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1251 /* Calculate levels for mip mapping */
1252 if (Levels == 0) {
1253 object->baseTexture.levels++;
1254 tmpW = EdgeLength;
1255 while (tmpW > 1) {
1256 tmpW = max(1, tmpW >> 1);
1257 object->baseTexture.levels++;
1259 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1262 /* Generate all the surfaces */
1263 tmpW = EdgeLength;
1264 for (i = 0; i < object->baseTexture.levels; i++) {
1266 /* Create the 6 faces */
1267 for (j = 0; j < 6; j++) {
1269 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1270 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1272 if(hr!= WINED3D_OK) {
1273 /* clean up */
1274 int k;
1275 int l;
1276 for (l = 0; l < j; l++) {
1277 IWineD3DSurface_Release(object->surfaces[j][i]);
1279 for (k = 0; k < i; k++) {
1280 for (l = 0; l < 6; l++) {
1281 IWineD3DSurface_Release(object->surfaces[l][j]);
1285 FIXME("(%p) Failed to create surface\n",object);
1286 HeapFree(GetProcessHeap(),0,object);
1287 *ppCubeTexture = NULL;
1288 return hr;
1290 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1291 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1293 tmpW = max(1, tmpW >> 1);
1296 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1297 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1298 return WINED3D_OK;
1301 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1305 if (NULL == ppQuery) {
1306 /* Just a check to see if we support this type of query */
1307 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1308 switch(Type) {
1309 case WINED3DQUERYTYPE_OCCLUSION:
1310 TRACE("(%p) occlusion query\n", This);
1311 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1312 hr = WINED3D_OK;
1313 else
1314 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1315 break;
1316 case WINED3DQUERYTYPE_VCACHE:
1317 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1318 case WINED3DQUERYTYPE_VERTEXSTATS:
1319 case WINED3DQUERYTYPE_EVENT:
1320 case WINED3DQUERYTYPE_TIMESTAMP:
1321 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1322 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1323 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1324 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1325 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1326 case WINED3DQUERYTYPE_PIXELTIMINGS:
1327 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1328 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1329 default:
1330 FIXME("(%p) Unhandled query type %d\n", This, Type);
1332 return hr;
1335 D3DCREATEOBJECTINSTANCE(object, Query)
1336 object->type = Type;
1337 /* allocated the 'extended' data based on the type of query requested */
1338 switch(Type){
1339 case WINED3DQUERYTYPE_OCCLUSION:
1340 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1341 TRACE("(%p) Allocating data for an occlusion query\n", This);
1342 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1343 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1344 break;
1346 case WINED3DQUERYTYPE_VCACHE:
1347 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1348 case WINED3DQUERYTYPE_VERTEXSTATS:
1349 case WINED3DQUERYTYPE_EVENT:
1350 case WINED3DQUERYTYPE_TIMESTAMP:
1351 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1352 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1353 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1354 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1355 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1356 case WINED3DQUERYTYPE_PIXELTIMINGS:
1357 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1358 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1359 default:
1360 object->extendedData = 0;
1361 FIXME("(%p) Unhandled query type %d\n",This , Type);
1363 TRACE("(%p) : Created Query %p\n", This, object);
1364 return WINED3D_OK;
1367 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1368 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1369 IUnknown* parent,
1370 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1371 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1374 HDC hDc;
1375 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1376 int num;
1377 XVisualInfo template;
1378 GLXContext oldContext;
1379 Drawable oldDrawable;
1380 HRESULT hr = WINED3D_OK;
1382 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1384 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1385 * does a device hold a reference to a swap chain giving them a lifetime of the device
1386 * or does the swap chain notify the device of its destruction.
1387 *******************************/
1389 /* Check the params */
1390 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1391 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1392 return WINED3DERR_INVALIDCALL;
1393 } else if (*pPresentationParameters->BackBufferCount > 1) {
1394 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");
1397 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1399 /*********************
1400 * Lookup the window Handle and the relating X window handle
1401 ********************/
1403 /* Setup hwnd we are using, plus which display this equates to */
1404 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1405 if (!object->win_handle) {
1406 object->win_handle = This->createParms.hFocusWindow;
1409 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1410 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1411 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1412 return WINED3DERR_NOTAVAILABLE;
1414 hDc = GetDC(object->win_handle);
1415 object->display = get_display(hDc);
1416 ReleaseDC(object->win_handle, hDc);
1417 TRACE("Using a display of %p %p\n", object->display, hDc);
1419 if (NULL == object->display || NULL == hDc) {
1420 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1421 return WINED3DERR_NOTAVAILABLE;
1424 if (object->win == 0) {
1425 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1426 return WINED3DERR_NOTAVAILABLE;
1429 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1430 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1433 * Create an opengl context for the display visual
1434 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1435 * use different properties after that point in time. FIXME: How to handle when requested format
1436 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1437 * it chooses is identical to the one already being used!
1438 **********************************/
1440 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1441 ENTER_GL();
1443 /* Create a new context for this swapchain */
1444 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1445 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1446 (or the best possible if none is requested) */
1447 TRACE("Found x visual ID : %ld\n", template.visualid);
1449 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1450 if (NULL == object->visInfo) {
1451 ERR("cannot really get XVisual\n");
1452 LEAVE_GL();
1453 return WINED3DERR_NOTAVAILABLE;
1454 } else {
1455 int n, value;
1456 /* Write out some debug info about the visual/s */
1457 TRACE("Using x visual ID : %ld\n", template.visualid);
1458 TRACE(" visual info: %p\n", object->visInfo);
1459 TRACE(" num items : %d\n", num);
1460 for (n = 0;n < num; n++) {
1461 TRACE("=====item=====: %d\n", n + 1);
1462 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1463 TRACE(" screen : %d\n", object->visInfo[n].screen);
1464 TRACE(" depth : %u\n", object->visInfo[n].depth);
1465 TRACE(" class : %d\n", object->visInfo[n].class);
1466 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1467 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1468 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1469 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1470 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1471 /* log some extra glx info */
1472 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1473 TRACE(" gl_aux_buffers : %d\n", value);
1474 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1475 TRACE(" gl_buffer_size : %d\n", value);
1476 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1477 TRACE(" gl_red_size : %d\n", value);
1478 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1479 TRACE(" gl_green_size : %d\n", value);
1480 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1481 TRACE(" gl_blue_size : %d\n", value);
1482 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1483 TRACE(" gl_alpha_size : %d\n", value);
1484 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1485 TRACE(" gl_depth_size : %d\n", value);
1486 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1487 TRACE(" gl_stencil_size : %d\n", value);
1489 /* Now choose a similar visual ID*/
1491 #ifdef USE_CONTEXT_MANAGER
1493 /** TODO: use a context mamager **/
1494 #endif
1497 IWineD3DSwapChain *implSwapChain;
1498 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1499 /* The first time around we create the context that is shared with all other swapchains and render targets */
1500 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1501 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1502 } else {
1504 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1505 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1506 /* and create a new context with the implicit swapchains context as the shared context */
1507 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1508 IWineD3DSwapChain_Release(implSwapChain);
1512 /* Cleanup */
1513 XFree(object->visInfo);
1514 object->visInfo = NULL;
1516 LEAVE_GL();
1518 if (!object->glCtx) {
1519 ERR("Failed to create GLX context\n");
1520 return WINED3DERR_NOTAVAILABLE;
1521 } else {
1522 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1523 object->win_handle, object->glCtx, object->win, object->visInfo);
1526 /*********************
1527 * Windowed / Fullscreen
1528 *******************/
1531 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1532 * so we should really check to see if there is a fullscreen swapchain already
1533 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1534 **************************************/
1536 if (!*(pPresentationParameters->Windowed)) {
1538 DEVMODEW devmode;
1539 HDC hdc;
1540 int bpp = 0;
1542 /* Get info on the current display setup */
1543 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1544 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1545 DeleteDC(hdc);
1547 /* Change the display settings */
1548 memset(&devmode, 0, sizeof(DEVMODEW));
1549 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1550 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1551 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1552 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1553 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1554 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1556 /* Make popup window */
1557 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1558 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1559 *(pPresentationParameters->BackBufferWidth),
1560 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1562 /* For GetDisplayMode */
1563 This->ddraw_width = devmode.dmPelsWidth;
1564 This->ddraw_height = devmode.dmPelsHeight;
1565 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1569 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1570 * then the corresponding dimension of the client area of the hDeviceWindow
1571 * (or the focus window, if hDeviceWindow is NULL) is taken.
1572 **********************/
1574 if (*(pPresentationParameters->Windowed) &&
1575 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1576 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1578 RECT Rect;
1579 GetClientRect(object->win_handle, &Rect);
1581 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1582 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1583 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1585 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1586 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1587 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1591 /*********************
1592 * finish off parameter initialization
1593 *******************/
1595 /* Put the correct figures in the presentation parameters */
1596 TRACE("Copying across presentation parameters\n");
1597 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1598 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1599 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1600 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1601 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1602 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1603 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1604 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1605 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1606 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1607 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1608 object->presentParms.Flags = *(pPresentationParameters->Flags);
1609 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1610 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1613 /*********************
1614 * Create the back, front and stencil buffers
1615 *******************/
1617 TRACE("calling rendertarget CB\n");
1618 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1619 parent,
1620 object->presentParms.BackBufferWidth,
1621 object->presentParms.BackBufferHeight,
1622 object->presentParms.BackBufferFormat,
1623 object->presentParms.MultiSampleType,
1624 object->presentParms.MultiSampleQuality,
1625 TRUE /* Lockable */,
1626 &object->frontBuffer,
1627 NULL /* pShared (always null)*/);
1628 if (object->frontBuffer != NULL)
1629 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1631 if(object->presentParms.BackBufferCount > 0) {
1632 int i;
1634 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1635 if(!object->backBuffer) {
1636 ERR("Out of memory\n");
1638 if (object->frontBuffer) {
1639 IUnknown *bufferParent;
1640 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1641 IUnknown_Release(bufferParent); /* once for the get parent */
1642 if (IUnknown_Release(bufferParent) > 0) {
1643 FIXME("(%p) Something's still holding the front buffer\n",This);
1646 HeapFree(GetProcessHeap(), 0, object);
1647 return E_OUTOFMEMORY;
1650 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1651 TRACE("calling rendertarget CB\n");
1652 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1653 parent,
1654 object->presentParms.BackBufferWidth,
1655 object->presentParms.BackBufferHeight,
1656 object->presentParms.BackBufferFormat,
1657 object->presentParms.MultiSampleType,
1658 object->presentParms.MultiSampleQuality,
1659 TRUE /* Lockable */,
1660 &object->backBuffer[i],
1661 NULL /* pShared (always null)*/);
1662 if(hr == WINED3D_OK && object->backBuffer[i]) {
1663 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1664 } else {
1665 break;
1668 } else {
1669 object->backBuffer = NULL;
1672 if (object->backBuffer != NULL) {
1673 ENTER_GL();
1674 glDrawBuffer(GL_BACK);
1675 checkGLcall("glDrawBuffer(GL_BACK)");
1676 LEAVE_GL();
1677 } else {
1678 /* Single buffering - draw to front buffer */
1679 ENTER_GL();
1680 glDrawBuffer(GL_FRONT);
1681 checkGLcall("glDrawBuffer(GL_FRONT)");
1682 LEAVE_GL();
1685 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1686 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1687 TRACE("Creating depth stencil buffer\n");
1688 if (This->depthStencilBuffer == NULL ) {
1689 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1690 parent,
1691 object->presentParms.BackBufferWidth,
1692 object->presentParms.BackBufferHeight,
1693 object->presentParms.AutoDepthStencilFormat,
1694 object->presentParms.MultiSampleType,
1695 object->presentParms.MultiSampleQuality,
1696 FALSE /* FIXME: Discard */,
1697 &This->depthStencilBuffer,
1698 NULL /* pShared (always null)*/ );
1699 if (This->depthStencilBuffer != NULL)
1700 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1703 /** TODO: A check on width, height and multisample types
1704 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1705 ****************************/
1706 object->wantsDepthStencilBuffer = TRUE;
1707 } else {
1708 object->wantsDepthStencilBuffer = FALSE;
1711 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1714 /*********************
1715 * init the default renderTarget management
1716 *******************/
1717 object->drawable = object->win;
1718 object->render_ctx = object->glCtx;
1720 if (hr == WINED3D_OK) {
1721 /*********************
1722 * Setup some defaults and clear down the buffers
1723 *******************/
1724 ENTER_GL();
1725 /** save current context and drawable **/
1726 oldContext = glXGetCurrentContext();
1727 oldDrawable = glXGetCurrentDrawable();
1729 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1730 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1731 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1733 checkGLcall("glXMakeCurrent");
1735 TRACE("Setting up the screen\n");
1736 /* Clear the screen */
1737 glClearColor(1.0, 0.0, 0.0, 0.0);
1738 checkGLcall("glClearColor");
1739 glClearIndex(0);
1740 glClearDepth(1);
1741 glClearStencil(0xffff);
1743 checkGLcall("glClear");
1745 glColor3f(1.0, 1.0, 1.0);
1746 checkGLcall("glColor3f");
1748 glEnable(GL_LIGHTING);
1749 checkGLcall("glEnable");
1751 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1752 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1754 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1755 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1757 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1758 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1760 /* switch back to the original context (if there was one)*/
1761 if (This->swapchains) {
1762 /** TODO: restore the context and drawable **/
1763 glXMakeCurrent(object->display, oldDrawable, oldContext);
1766 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1767 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1768 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1769 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1770 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1772 LEAVE_GL();
1774 TRACE("Set swapchain to %p\n", object);
1775 } else { /* something went wrong so clean up */
1776 IUnknown* bufferParent;
1777 if (object->frontBuffer) {
1779 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1780 IUnknown_Release(bufferParent); /* once for the get parent */
1781 if (IUnknown_Release(bufferParent) > 0) {
1782 FIXME("(%p) Something's still holding the front buffer\n",This);
1785 if (object->backBuffer) {
1786 int i;
1787 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1788 if(object->backBuffer[i]) {
1789 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1790 IUnknown_Release(bufferParent); /* once for the get parent */
1791 if (IUnknown_Release(bufferParent) > 0) {
1792 FIXME("(%p) Something's still holding the back buffer\n",This);
1796 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1797 object->backBuffer = NULL;
1799 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1800 /* Clean up the context */
1801 /* check that we are the current context first (we shouldn't be though!) */
1802 if (object->glCtx != 0) {
1803 if(glXGetCurrentContext() == object->glCtx) {
1804 glXMakeCurrent(object->display, None, NULL);
1806 glXDestroyContext(object->display, object->glCtx);
1808 HeapFree(GetProcessHeap(), 0, object);
1812 return hr;
1815 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1816 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1818 TRACE("(%p)\n", This);
1820 return This->NumberOfSwapChains;
1823 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1825 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1827 if(iSwapChain < This->NumberOfSwapChains) {
1828 *pSwapChain = This->swapchains[iSwapChain];
1829 IWineD3DSwapChain_AddRef(*pSwapChain);
1830 TRACE("(%p) returning %p\n", This, *pSwapChain);
1831 return WINED3D_OK;
1832 } else {
1833 TRACE("Swapchain out of range\n");
1834 *pSwapChain = NULL;
1835 return WINED3DERR_INVALIDCALL;
1839 /*****
1840 * Vertex Declaration
1841 *****/
1842 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1844 IWineD3DVertexDeclarationImpl *object = NULL;
1845 HRESULT hr = WINED3D_OK;
1846 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1847 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1848 object->allFVF = 0;
1850 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1852 return hr;
1855 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1856 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1858 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1859 HRESULT hr = WINED3D_OK;
1860 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1861 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1863 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1865 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1866 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1867 if (pDeclaration != NULL) {
1868 IWineD3DVertexDeclaration *vertexDeclaration;
1869 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1870 if (WINED3D_OK == hr) {
1871 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1872 object->vertexDeclaration = vertexDeclaration;
1873 } else {
1874 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1875 IWineD3DVertexShader_Release(*ppVertexShader);
1876 return WINED3DERR_INVALIDCALL;
1880 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1882 if (WINED3D_OK != hr) {
1883 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1884 IWineD3DVertexShader_Release(*ppVertexShader);
1885 return WINED3DERR_INVALIDCALL;
1888 #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. */
1889 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1890 /* Foo */
1891 } else {
1892 /* Bar */
1895 #endif
1897 return WINED3D_OK;
1900 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1902 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1903 HRESULT hr = WINED3D_OK;
1905 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1906 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1907 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1908 if (WINED3D_OK == hr) {
1909 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1910 } else {
1911 WARN("(%p) : Failed to create pixel shader\n", This);
1914 return hr;
1917 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1919 IWineD3DPaletteImpl *object;
1920 HRESULT hr;
1921 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1923 /* Create the new object */
1924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1925 if(!object) {
1926 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1927 return E_OUTOFMEMORY;
1930 object->lpVtbl = &IWineD3DPalette_Vtbl;
1931 object->ref = 1;
1932 object->Flags = Flags;
1933 object->parent = Parent;
1934 object->wineD3DDevice = This;
1935 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1937 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1939 if(!object->hpal) {
1940 HeapFree( GetProcessHeap(), 0, object);
1941 return E_OUTOFMEMORY;
1944 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1945 if(FAILED(hr)) {
1946 IWineD3DPalette_Release((IWineD3DPalette *) object);
1947 return hr;
1950 *Palette = (IWineD3DPalette *) object;
1952 return WINED3D_OK;
1955 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1957 IWineD3DSwapChainImpl *swapchain;
1958 DWORD state;
1960 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1961 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1963 /* TODO: Test if OpenGL is compiled in and loaded */
1965 /* Initialize the texture unit mapping to a 1:1 mapping */
1966 for(state = 0; state < MAX_SAMPLERS; state++) {
1967 This->texUnitMap[state] = state;
1969 This->oneToOneTexUnitMap = TRUE;
1971 /* Setup the implicit swapchain */
1972 TRACE("Creating implicit swapchain\n");
1973 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1974 WARN("Failed to create implicit swapchain\n");
1975 return WINED3DERR_INVALIDCALL;
1978 This->NumberOfSwapChains = 1;
1979 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1980 if(!This->swapchains) {
1981 ERR("Out of memory!\n");
1982 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1983 return E_OUTOFMEMORY;
1985 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1987 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1988 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1989 This->render_targets[0] = swapchain->backBuffer[0];
1991 else {
1992 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1993 This->render_targets[0] = swapchain->frontBuffer;
1995 IWineD3DSurface_AddRef(This->render_targets[0]);
1996 /* Depth Stencil support */
1997 This->stencilBufferTarget = This->depthStencilBuffer;
1998 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1999 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
2001 if (NULL != This->stencilBufferTarget) {
2002 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2005 /* Set up some starting GL setup */
2006 ENTER_GL();
2008 * Initialize openGL extension related variables
2009 * with Default values
2012 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2013 /* Setup all the devices defaults */
2014 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2015 #if 0
2016 IWineD3DImpl_CheckGraphicsMemory();
2017 #endif
2018 LEAVE_GL();
2020 /* Initialize our list of GLSL programs */
2021 list_init(&This->glsl_shader_progs);
2023 { /* Set a default viewport */
2024 WINED3DVIEWPORT vp;
2025 vp.X = 0;
2026 vp.Y = 0;
2027 vp.Width = *(pPresentationParameters->BackBufferWidth);
2028 vp.Height = *(pPresentationParameters->BackBufferHeight);
2029 vp.MinZ = 0.0f;
2030 vp.MaxZ = 1.0f;
2031 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2034 /* Initialize the current view state */
2035 This->modelview_valid = 1;
2036 This->proj_valid = 0;
2037 This->view_ident = 1;
2038 This->last_was_rhw = 0;
2039 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2040 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2042 /* Clear the screen */
2043 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2045 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
2046 * This might create a problem in 2 situations:
2047 * ->The D3D default value is 0, but the opengl default value is something else
2048 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
2050 for(state = 0; state <= STATE_HIGHEST; state++) {
2051 IWineD3DDeviceImpl_MarkStateDirty(This, state);
2054 This->d3d_initialized = TRUE;
2055 return WINED3D_OK;
2058 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2060 int sampler;
2061 uint i;
2062 TRACE("(%p)\n", This);
2064 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2066 /* Delete the mouse cursor texture */
2067 if(This->cursorTexture) {
2068 ENTER_GL();
2069 glDeleteTextures(1, &This->cursorTexture);
2070 LEAVE_GL();
2071 This->cursorTexture = 0;
2074 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2075 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2078 /* Release the buffers (with sanity checks)*/
2079 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2080 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2081 if(This->depthStencilBuffer != This->stencilBufferTarget)
2082 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2084 This->stencilBufferTarget = NULL;
2086 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2087 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2088 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2090 TRACE("Setting rendertarget to NULL\n");
2091 This->render_targets[0] = NULL;
2093 if (This->depthStencilBuffer) {
2094 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2095 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2097 This->depthStencilBuffer = NULL;
2100 for(i=0; i < This->NumberOfSwapChains; i++) {
2101 TRACE("Releasing the implicit swapchain %d\n", i);
2102 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2103 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2107 HeapFree(GetProcessHeap(), 0, This->swapchains);
2108 This->swapchains = NULL;
2109 This->NumberOfSwapChains = 0;
2111 This->d3d_initialized = FALSE;
2112 return WINED3D_OK;
2115 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2117 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2119 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2120 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2121 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2122 * separately.
2124 This->ddraw_fullscreen = fullscreen;
2127 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2130 DEVMODEW DevModeW;
2131 int i;
2132 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2134 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2136 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2137 /* Ignore some modes if a description was passed */
2138 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2139 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2140 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2142 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2144 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2145 return D3D_OK;
2148 return D3D_OK;
2151 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2152 DEVMODEW devmode;
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2154 LONG ret;
2155 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2156 RECT clip_rc;
2158 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2160 /* Resize the screen even without a window:
2161 * The app could have unset it with SetCooperativeLevel, but not called
2162 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2163 * but we don't have any hwnd
2166 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2167 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2168 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2169 devmode.dmPelsWidth = pMode->Width;
2170 devmode.dmPelsHeight = pMode->Height;
2172 devmode.dmDisplayFrequency = pMode->RefreshRate;
2173 if (pMode->RefreshRate != 0) {
2174 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2177 /* Only change the mode if necessary */
2178 if( (This->ddraw_width == pMode->Width) &&
2179 (This->ddraw_height == pMode->Height) &&
2180 (This->ddraw_format == pMode->Format) &&
2181 (pMode->RefreshRate == 0) ) {
2182 return D3D_OK;
2185 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2186 if (ret != DISP_CHANGE_SUCCESSFUL) {
2187 if(devmode.dmDisplayFrequency != 0) {
2188 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2189 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2190 devmode.dmDisplayFrequency = 0;
2191 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2193 if(ret != DISP_CHANGE_SUCCESSFUL) {
2194 return DDERR_INVALIDMODE;
2198 /* Store the new values */
2199 This->ddraw_width = pMode->Width;
2200 This->ddraw_height = pMode->Height;
2201 This->ddraw_format = pMode->Format;
2203 /* Only do this with a window of course */
2204 if(This->ddraw_window)
2205 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2207 /* And finally clip mouse to our screen */
2208 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2209 ClipCursor(&clip_rc);
2211 return WINED3D_OK;
2214 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2216 *ppD3D= This->wineD3D;
2217 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2218 IWineD3D_AddRef(*ppD3D);
2219 return WINED3D_OK;
2222 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2223 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2224 * into the video ram as possible and seeing how many fit
2225 * you can also get the correct initial value from nvidia and ATI's driver via X
2226 * texture memory is video memory + AGP memory
2227 *******************/
2228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2229 static BOOL showfixmes = TRUE;
2230 if (showfixmes) {
2231 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2232 (wined3d_settings.emulated_textureram/(1024*1024)),
2233 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2234 showfixmes = FALSE;
2236 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2237 (wined3d_settings.emulated_textureram/(1024*1024)),
2238 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2239 /* return simulated texture memory left */
2240 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2245 /*****
2246 * Get / Set FVF
2247 *****/
2248 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2250 HRESULT hr = WINED3D_OK;
2252 /* Update the current state block */
2253 This->updateStateBlock->fvf = fvf;
2254 This->updateStateBlock->changed.fvf = TRUE;
2255 This->updateStateBlock->set.fvf = TRUE;
2257 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2258 return hr;
2262 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2264 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2265 *pfvf = This->stateBlock->fvf;
2266 return WINED3D_OK;
2269 /*****
2270 * Get / Set Stream Source
2271 *****/
2272 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 IWineD3DVertexBuffer *oldSrc;
2276 /**TODO: instance and index data, see
2277 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2279 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2280 **************/
2282 /* D3d9 only, but shouldn't hurt d3d8 */
2283 UINT streamFlags;
2285 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2286 if (streamFlags) {
2287 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2288 FIXME("stream index data not supported\n");
2290 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2291 FIXME("stream instance data not supported\n");
2295 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2297 if (StreamNumber >= MAX_STREAMS) {
2298 WARN("Stream out of range %d\n", StreamNumber);
2299 return WINED3DERR_INVALIDCALL;
2302 oldSrc = This->stateBlock->streamSource[StreamNumber];
2303 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2305 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2306 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2307 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2308 if (pStreamData) {
2309 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2310 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2312 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2314 /* Handle recording of state blocks */
2315 if (This->isRecordingState) {
2316 TRACE("Recording... not performing anything\n");
2317 return WINED3D_OK;
2320 /* Same stream object: no action */
2321 if (oldSrc == pStreamData)
2322 return WINED3D_OK;
2324 /* Need to do a getParent and pass the reffs up */
2325 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2326 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2327 so for now, just count internally */
2328 if (pStreamData != NULL) {
2329 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2330 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2331 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2333 vbImpl->stream = StreamNumber;
2334 vbImpl->Flags |= VBFLAG_STREAM;
2335 IWineD3DVertexBuffer_AddRef(pStreamData);
2337 if (oldSrc != NULL) {
2338 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2339 IWineD3DVertexBuffer_Release(oldSrc);
2342 return WINED3D_OK;
2345 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2347 UINT streamFlags;
2349 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2350 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2353 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2354 if (streamFlags) {
2355 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2356 FIXME("stream index data not supported\n");
2358 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2359 FIXME("stream instance data not supported\n");
2363 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2365 if (StreamNumber >= MAX_STREAMS) {
2366 WARN("Stream out of range %d\n", StreamNumber);
2367 return WINED3DERR_INVALIDCALL;
2369 *pStream = This->stateBlock->streamSource[StreamNumber];
2370 *pStride = This->stateBlock->streamStride[StreamNumber];
2371 if (pOffset) {
2372 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2375 if (*pStream != NULL) {
2376 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2378 return WINED3D_OK;
2381 /*Should be quite easy, just an extension of vertexdata
2382 ref...
2383 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2385 The divider is a bit odd though
2387 VertexOffset = StartVertex / Divider * StreamStride +
2388 VertexIndex / Divider * StreamStride + StreamOffset
2391 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2395 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2397 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2398 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2399 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2401 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2402 FIXME("Stream indexing not fully supported\n");
2405 return WINED3D_OK;
2408 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2411 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2412 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2414 TRACE("(%p) : returning %d\n", This, *Divider);
2416 return WINED3D_OK;
2419 /*****
2420 * Get / Set & Multiply Transform
2421 *****/
2422 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 /* Most of this routine, comments included copied from ddraw tree initially: */
2426 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2428 /* Handle recording of state blocks */
2429 if (This->isRecordingState) {
2430 TRACE("Recording... not performing anything\n");
2431 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2432 This->updateStateBlock->set.transform[d3dts] = TRUE;
2433 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2434 return WINED3D_OK;
2438 * If the new matrix is the same as the current one,
2439 * we cut off any further processing. this seems to be a reasonable
2440 * optimization because as was noticed, some apps (warcraft3 for example)
2441 * tend towards setting the same matrix repeatedly for some reason.
2443 * From here on we assume that the new matrix is different, wherever it matters.
2445 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2446 TRACE("The app is setting the same matrix over again\n");
2447 return WINED3D_OK;
2448 } else {
2449 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2453 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2454 where ViewMat = Camera space, WorldMat = world space.
2456 In OpenGL, camera and world space is combined into GL_MODELVIEW
2457 matrix. The Projection matrix stay projection matrix.
2460 /* Capture the times we can just ignore the change for now */
2461 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2462 This->modelview_valid = FALSE;
2463 return WINED3D_OK;
2465 } else if (d3dts == WINED3DTS_PROJECTION) {
2466 This->proj_valid = FALSE;
2467 return WINED3D_OK;
2469 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2470 /* Indexed Vertex Blending Matrices 256 -> 511 */
2471 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2472 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2473 return WINED3D_OK;
2476 /* Now we really are going to have to change a matrix */
2477 ENTER_GL();
2479 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2480 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2481 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2482 unsigned int k;
2484 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2485 * NOTE: We have to reset the positions even if the light/plane is not currently
2486 * enabled, since the call to enable it will not reset the position.
2487 * NOTE2: Apparently texture transforms do NOT need reapplying
2490 PLIGHTINFOEL *lightChain = NULL;
2491 This->modelview_valid = FALSE;
2492 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2494 glMatrixMode(GL_MODELVIEW);
2495 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2496 glPushMatrix();
2497 glLoadMatrixf((const float *)lpmatrix);
2498 checkGLcall("glLoadMatrixf(...)");
2500 /* Reset lights */
2501 lightChain = This->stateBlock->lights;
2502 while (lightChain && lightChain->glIndex != -1) {
2503 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2504 checkGLcall("glLightfv posn");
2505 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2506 checkGLcall("glLightfv dirn");
2507 lightChain = lightChain->next;
2510 /* Reset Clipping Planes if clipping is enabled */
2511 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2512 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2513 checkGLcall("glClipPlane");
2515 glPopMatrix();
2517 } else { /* What was requested!?? */
2518 WARN("invalid matrix specified: %i\n", d3dts);
2521 /* Release lock, all done */
2522 LEAVE_GL();
2523 return WINED3D_OK;
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2529 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2530 return WINED3D_OK;
2533 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2534 WINED3DMATRIX *mat = NULL;
2535 WINED3DMATRIX temp;
2537 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2538 * below means it will be recorded in a state block change, but it
2539 * works regardless where it is recorded.
2540 * If this is found to be wrong, change to StateBlock.
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2545 if (State < HIGHEST_TRANSFORMSTATE)
2547 mat = &This->updateStateBlock->transforms[State];
2548 } else {
2549 FIXME("Unhandled transform state!!\n");
2552 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2554 /* Apply change via set transform - will reapply to eg. lights this way */
2555 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2558 /*****
2559 * Get / Set Light
2560 *****/
2561 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2562 you can reference any indexes you want as long as that number max are enabled at any
2563 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2564 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2565 but when recording, just build a chain pretty much of commands to be replayed. */
2567 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2568 float rho;
2569 PLIGHTINFOEL *object, *temp;
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2572 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2574 /* If recording state block, just add to end of lights chain */
2575 if (This->isRecordingState) {
2576 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2577 if (NULL == object) {
2578 return WINED3DERR_OUTOFVIDEOMEMORY;
2580 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2581 object->OriginalIndex = Index;
2582 object->glIndex = -1;
2583 object->changed = TRUE;
2585 /* Add to the END of the chain of lights changes to be replayed */
2586 if (This->updateStateBlock->lights == NULL) {
2587 This->updateStateBlock->lights = object;
2588 } else {
2589 temp = This->updateStateBlock->lights;
2590 while (temp->next != NULL) temp=temp->next;
2591 temp->next = object;
2593 TRACE("Recording... not performing anything more\n");
2594 return WINED3D_OK;
2597 /* Ok, not recording any longer so do real work */
2598 object = This->stateBlock->lights;
2599 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2601 /* If we didn't find it in the list of lights, time to add it */
2602 if (object == NULL) {
2603 PLIGHTINFOEL *insertAt,*prevPos;
2605 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2606 if (NULL == object) {
2607 return WINED3DERR_OUTOFVIDEOMEMORY;
2609 object->OriginalIndex = Index;
2610 object->glIndex = -1;
2612 /* Add it to the front of list with the idea that lights will be changed as needed
2613 BUT after any lights currently assigned GL indexes */
2614 insertAt = This->stateBlock->lights;
2615 prevPos = NULL;
2616 while (insertAt != NULL && insertAt->glIndex != -1) {
2617 prevPos = insertAt;
2618 insertAt = insertAt->next;
2621 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2622 This->stateBlock->lights = object;
2623 } else if (insertAt == NULL) { /* End of list */
2624 prevPos->next = object;
2625 object->prev = prevPos;
2626 } else { /* Middle of chain */
2627 if (prevPos == NULL) {
2628 This->stateBlock->lights = object;
2629 } else {
2630 prevPos->next = object;
2632 object->prev = prevPos;
2633 object->next = insertAt;
2634 insertAt->prev = object;
2638 /* Initialize the object */
2639 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,
2640 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2641 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2642 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2643 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2644 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2645 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2647 /* Save away the information */
2648 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2650 switch (pLight->Type) {
2651 case WINED3DLIGHT_POINT:
2652 /* Position */
2653 object->lightPosn[0] = pLight->Position.x;
2654 object->lightPosn[1] = pLight->Position.y;
2655 object->lightPosn[2] = pLight->Position.z;
2656 object->lightPosn[3] = 1.0f;
2657 object->cutoff = 180.0f;
2658 /* FIXME: Range */
2659 break;
2661 case WINED3DLIGHT_DIRECTIONAL:
2662 /* Direction */
2663 object->lightPosn[0] = -pLight->Direction.x;
2664 object->lightPosn[1] = -pLight->Direction.y;
2665 object->lightPosn[2] = -pLight->Direction.z;
2666 object->lightPosn[3] = 0.0;
2667 object->exponent = 0.0f;
2668 object->cutoff = 180.0f;
2669 break;
2671 case WINED3DLIGHT_SPOT:
2672 /* Position */
2673 object->lightPosn[0] = pLight->Position.x;
2674 object->lightPosn[1] = pLight->Position.y;
2675 object->lightPosn[2] = pLight->Position.z;
2676 object->lightPosn[3] = 1.0;
2678 /* Direction */
2679 object->lightDirn[0] = pLight->Direction.x;
2680 object->lightDirn[1] = pLight->Direction.y;
2681 object->lightDirn[2] = pLight->Direction.z;
2682 object->lightDirn[3] = 1.0;
2685 * opengl-ish and d3d-ish spot lights use too different models for the
2686 * light "intensity" as a function of the angle towards the main light direction,
2687 * so we only can approximate very roughly.
2688 * however spot lights are rather rarely used in games (if ever used at all).
2689 * furthermore if still used, probably nobody pays attention to such details.
2691 if (pLight->Falloff == 0) {
2692 rho = 6.28f;
2693 } else {
2694 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2696 if (rho < 0.0001) rho = 0.0001f;
2697 object->exponent = -0.3/log(cos(rho/2));
2698 if (object->exponent > 128.0) {
2699 object->exponent = 128.0;
2701 object->cutoff = pLight->Phi*90/M_PI;
2703 /* FIXME: Range */
2704 break;
2706 default:
2707 FIXME("Unrecognized light type %d\n", pLight->Type);
2710 /* Update the live definitions if the light is currently assigned a glIndex */
2711 if (object->glIndex != -1) {
2712 setup_light(iface, object->glIndex, object);
2714 return WINED3D_OK;
2717 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2718 PLIGHTINFOEL *lightInfo = NULL;
2719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2720 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2722 /* Locate the light in the live lights */
2723 lightInfo = This->stateBlock->lights;
2724 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2726 if (lightInfo == NULL) {
2727 TRACE("Light information requested but light not defined\n");
2728 return WINED3DERR_INVALIDCALL;
2731 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2732 return WINED3D_OK;
2735 /*****
2736 * Get / Set Light Enable
2737 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2738 *****/
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2740 PLIGHTINFOEL *lightInfo = NULL;
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2744 /* Tests show true = 128...not clear why */
2746 Enable = Enable? 128: 0;
2748 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2749 if (This->isRecordingState) {
2750 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2751 if (NULL == lightInfo) {
2752 return WINED3DERR_OUTOFVIDEOMEMORY;
2754 lightInfo->OriginalIndex = Index;
2755 lightInfo->glIndex = -1;
2756 lightInfo->enabledChanged = TRUE;
2757 lightInfo->lightEnabled = Enable;
2759 /* Add to the END of the chain of lights changes to be replayed */
2760 if (This->updateStateBlock->lights == NULL) {
2761 This->updateStateBlock->lights = lightInfo;
2762 } else {
2763 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2764 while (temp->next != NULL) temp=temp->next;
2765 temp->next = lightInfo;
2767 TRACE("Recording... not performing anything more\n");
2768 return WINED3D_OK;
2771 /* Not recording... So, locate the light in the live lights */
2772 lightInfo = This->stateBlock->lights;
2773 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2775 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2776 if (lightInfo == NULL) {
2778 TRACE("Light enabled requested but light not defined, so defining one!\n");
2779 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2781 /* Search for it again! Should be fairly quick as near head of list */
2782 lightInfo = This->stateBlock->lights;
2783 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2784 if (lightInfo == NULL) {
2785 FIXME("Adding default lights has failed dismally\n");
2786 return WINED3DERR_INVALIDCALL;
2790 /* OK, we now have a light... */
2791 if (!Enable) {
2793 /* If we are disabling it, check it was enabled, and
2794 still only do something if it has assigned a glIndex (which it should have!) */
2795 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2796 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2797 ENTER_GL();
2798 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2799 checkGLcall("glDisable GL_LIGHT0+Index");
2800 LEAVE_GL();
2801 } else {
2802 TRACE("Nothing to do as light was not enabled\n");
2804 lightInfo->lightEnabled = Enable;
2805 } else {
2807 /* We are enabling it. If it is enabled, it's really simple */
2808 if (lightInfo->lightEnabled) {
2809 /* nop */
2810 TRACE("Nothing to do as light was enabled\n");
2812 /* If it already has a glIndex, it's still simple */
2813 } else if (lightInfo->glIndex != -1) {
2814 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2815 lightInfo->lightEnabled = Enable;
2816 ENTER_GL();
2817 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2818 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2819 LEAVE_GL();
2821 /* Otherwise got to find space - lights are ordered gl indexes first */
2822 } else {
2823 PLIGHTINFOEL *bsf = NULL;
2824 PLIGHTINFOEL *pos = This->stateBlock->lights;
2825 PLIGHTINFOEL *prev = NULL;
2826 int Index= 0;
2827 int glIndex = -1;
2829 /* Try to minimize changes as much as possible */
2830 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2832 /* Try to remember which index can be replaced if necessary */
2833 if (bsf==NULL && !pos->lightEnabled) {
2834 /* Found a light we can replace, save as best replacement */
2835 bsf = pos;
2838 /* Step to next space */
2839 prev = pos;
2840 pos = pos->next;
2841 Index ++;
2844 /* If we have too many active lights, fail the call */
2845 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2846 FIXME("Program requests too many concurrent lights\n");
2847 return WINED3DERR_INVALIDCALL;
2849 /* If we have allocated all lights, but not all are enabled,
2850 reuse one which is not enabled */
2851 } else if (Index == This->maxConcurrentLights) {
2852 /* use bsf - Simply swap the new light and the BSF one */
2853 PLIGHTINFOEL *bsfNext = bsf->next;
2854 PLIGHTINFOEL *bsfPrev = bsf->prev;
2856 /* Sort out ends */
2857 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2858 if (bsf->prev != NULL) {
2859 bsf->prev->next = lightInfo;
2860 } else {
2861 This->stateBlock->lights = lightInfo;
2864 /* If not side by side, lots of chains to update */
2865 if (bsf->next != lightInfo) {
2866 lightInfo->prev->next = bsf;
2867 bsf->next->prev = lightInfo;
2868 bsf->next = lightInfo->next;
2869 bsf->prev = lightInfo->prev;
2870 lightInfo->next = bsfNext;
2871 lightInfo->prev = bsfPrev;
2873 } else {
2874 /* Simple swaps */
2875 bsf->prev = lightInfo;
2876 bsf->next = lightInfo->next;
2877 lightInfo->next = bsf;
2878 lightInfo->prev = bsfPrev;
2882 /* Update states */
2883 glIndex = bsf->glIndex;
2884 bsf->glIndex = -1;
2885 lightInfo->glIndex = glIndex;
2886 lightInfo->lightEnabled = Enable;
2888 /* Finally set up the light in gl itself */
2889 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2890 ENTER_GL();
2891 setup_light(iface, glIndex, lightInfo);
2892 glEnable(GL_LIGHT0 + glIndex);
2893 checkGLcall("glEnable GL_LIGHT0 new setup");
2894 LEAVE_GL();
2896 /* If we reached the end of the allocated lights, with space in the
2897 gl lights, setup a new light */
2898 } else if (pos->glIndex == -1) {
2900 /* We reached the end of the allocated gl lights, so already
2901 know the index of the next one! */
2902 glIndex = Index;
2903 lightInfo->glIndex = glIndex;
2904 lightInfo->lightEnabled = Enable;
2906 /* In an ideal world, it's already in the right place */
2907 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2908 /* No need to move it */
2909 } else {
2910 /* Remove this light from the list */
2911 lightInfo->prev->next = lightInfo->next;
2912 if (lightInfo->next != NULL) {
2913 lightInfo->next->prev = lightInfo->prev;
2916 /* Add in at appropriate place (inbetween prev and pos) */
2917 lightInfo->prev = prev;
2918 lightInfo->next = pos;
2919 if (prev == NULL) {
2920 This->stateBlock->lights = lightInfo;
2921 } else {
2922 prev->next = lightInfo;
2924 if (pos != NULL) {
2925 pos->prev = lightInfo;
2929 /* Finally set up the light in gl itself */
2930 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
2931 ENTER_GL();
2932 setup_light(iface, glIndex, lightInfo);
2933 glEnable(GL_LIGHT0 + glIndex);
2934 checkGLcall("glEnable GL_LIGHT0 new setup");
2935 LEAVE_GL();
2940 return WINED3D_OK;
2943 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2945 PLIGHTINFOEL *lightInfo = NULL;
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 TRACE("(%p) : for idx(%d)\n", This, Index);
2949 /* Locate the light in the live lights */
2950 lightInfo = This->stateBlock->lights;
2951 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2953 if (lightInfo == NULL) {
2954 TRACE("Light enabled state requested but light not defined\n");
2955 return WINED3DERR_INVALIDCALL;
2957 *pEnable = lightInfo->lightEnabled;
2958 return WINED3D_OK;
2961 /*****
2962 * Get / Set Clip Planes
2963 *****/
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2968 /* Validate Index */
2969 if (Index >= GL_LIMITS(clipplanes)) {
2970 TRACE("Application has requested clipplane this device doesn't support\n");
2971 return WINED3DERR_INVALIDCALL;
2974 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2975 This->updateStateBlock->set.clipplane[Index] = TRUE;
2976 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2977 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2978 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2979 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2981 /* Handle recording of state blocks */
2982 if (This->isRecordingState) {
2983 TRACE("Recording... not performing anything\n");
2984 return WINED3D_OK;
2987 /* Apply it */
2989 ENTER_GL();
2991 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2992 glMatrixMode(GL_MODELVIEW);
2993 glPushMatrix();
2994 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2996 TRACE("Clipplane [%f,%f,%f,%f]\n",
2997 This->updateStateBlock->clipplane[Index][0],
2998 This->updateStateBlock->clipplane[Index][1],
2999 This->updateStateBlock->clipplane[Index][2],
3000 This->updateStateBlock->clipplane[Index][3]);
3001 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3002 checkGLcall("glClipPlane");
3004 glPopMatrix();
3005 LEAVE_GL();
3007 return WINED3D_OK;
3010 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 TRACE("(%p) : for idx %d\n", This, Index);
3014 /* Validate Index */
3015 if (Index >= GL_LIMITS(clipplanes)) {
3016 TRACE("Application has requested clipplane this device doesn't support\n");
3017 return WINED3DERR_INVALIDCALL;
3020 pPlane[0] = This->stateBlock->clipplane[Index][0];
3021 pPlane[1] = This->stateBlock->clipplane[Index][1];
3022 pPlane[2] = This->stateBlock->clipplane[Index][2];
3023 pPlane[3] = This->stateBlock->clipplane[Index][3];
3024 return WINED3D_OK;
3027 /*****
3028 * Get / Set Clip Plane Status
3029 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3030 *****/
3031 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 FIXME("(%p) : stub\n", This);
3034 if (NULL == pClipStatus) {
3035 return WINED3DERR_INVALIDCALL;
3037 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3038 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 FIXME("(%p) : stub\n", This);
3045 if (NULL == pClipStatus) {
3046 return WINED3DERR_INVALIDCALL;
3048 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3049 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3050 return WINED3D_OK;
3053 /*****
3054 * Get / Set Material
3055 *****/
3056 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 This->updateStateBlock->changed.material = TRUE;
3060 This->updateStateBlock->set.material = TRUE;
3061 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3063 /* Handle recording of state blocks */
3064 if (This->isRecordingState) {
3065 TRACE("Recording... not performing anything\n");
3066 return WINED3D_OK;
3069 ENTER_GL();
3070 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3071 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3072 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3073 pMaterial->Ambient.b, pMaterial->Ambient.a);
3074 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3075 pMaterial->Specular.b, pMaterial->Specular.a);
3076 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3077 pMaterial->Emissive.b, pMaterial->Emissive.a);
3078 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3080 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3081 checkGLcall("glMaterialfv(GL_AMBIENT)");
3082 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3083 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3085 /* Only change material color if specular is enabled, otherwise it is set to black */
3086 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3087 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3088 checkGLcall("glMaterialfv(GL_SPECULAR");
3089 } else {
3090 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3091 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3092 checkGLcall("glMaterialfv(GL_SPECULAR");
3094 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3095 checkGLcall("glMaterialfv(GL_EMISSION)");
3096 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3097 checkGLcall("glMaterialf(GL_SHININESS");
3099 LEAVE_GL();
3100 return WINED3D_OK;
3103 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3106 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3107 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3108 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3109 pMaterial->Ambient.b, pMaterial->Ambient.a);
3110 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3111 pMaterial->Specular.b, pMaterial->Specular.a);
3112 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3113 pMaterial->Emissive.b, pMaterial->Emissive.a);
3114 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3116 return WINED3D_OK;
3119 /*****
3120 * Get / Set Indices
3121 *****/
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3123 UINT BaseVertexIndex) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 IWineD3DIndexBuffer *oldIdxs;
3127 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3128 oldIdxs = This->updateStateBlock->pIndexData;
3130 This->updateStateBlock->changed.indices = TRUE;
3131 This->updateStateBlock->set.indices = TRUE;
3132 This->updateStateBlock->pIndexData = pIndexData;
3133 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3135 /* Handle recording of state blocks */
3136 if (This->isRecordingState) {
3137 TRACE("Recording... not performing anything\n");
3138 return WINED3D_OK;
3141 if (NULL != pIndexData) {
3142 IWineD3DIndexBuffer_AddRef(pIndexData);
3144 if (NULL != oldIdxs) {
3145 IWineD3DIndexBuffer_Release(oldIdxs);
3147 return WINED3D_OK;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 *ppIndexData = This->stateBlock->pIndexData;
3155 /* up ref count on ppindexdata */
3156 if (*ppIndexData) {
3157 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3158 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3159 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3160 }else{
3161 TRACE("(%p) No index data set\n", This);
3163 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3165 return WINED3D_OK;
3168 /*****
3169 * Get / Set Viewports
3170 *****/
3171 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 TRACE("(%p)\n", This);
3175 This->updateStateBlock->changed.viewport = TRUE;
3176 This->updateStateBlock->set.viewport = TRUE;
3177 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3179 /* Handle recording of state blocks */
3180 if (This->isRecordingState) {
3181 TRACE("Recording... not performing anything\n");
3182 return WINED3D_OK;
3184 This->viewport_changed = TRUE;
3186 ENTER_GL();
3188 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3189 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3191 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3192 checkGLcall("glDepthRange");
3193 /* Note: GL requires lower left, DirectX supplies upper left */
3194 /* TODO: replace usage of renderTarget with context management */
3195 glViewport(pViewport->X,
3196 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3197 pViewport->Width, pViewport->Height);
3199 checkGLcall("glViewport");
3201 LEAVE_GL();
3203 return WINED3D_OK;
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p)\n", This);
3210 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3211 return WINED3D_OK;
3214 /*****
3215 * Get / Set Render States
3216 * TODO: Verify against dx9 definitions
3217 *****/
3218 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 DWORD oldValue = This->stateBlock->renderState[State];
3223 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3225 This->updateStateBlock->changed.renderState[State] = TRUE;
3226 This->updateStateBlock->set.renderState[State] = TRUE;
3227 This->updateStateBlock->renderState[State] = Value;
3229 /* Handle recording of state blocks */
3230 if (This->isRecordingState) {
3231 TRACE("Recording... not performing anything\n");
3232 return WINED3D_OK;
3235 /* Compared here and not before the assignment to allow proper stateblock recording */
3236 if(Value == oldValue) {
3237 TRACE("Application is setting the old value over, nothing to do\n");
3238 } else {
3239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3242 return WINED3D_OK;
3245 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3248 *pValue = This->stateBlock->renderState[State];
3249 return WINED3D_OK;
3252 /*****
3253 * Get / Set Sampler States
3254 * TODO: Verify against dx9 definitions
3255 *****/
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
3262 * SetSampler is designed to allow for more than the standard up to 8 textures
3263 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3264 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3266 * http://developer.nvidia.com/object/General_FAQ.html#t6
3268 * There are two new settings for GForce
3269 * the sampler one:
3270 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3271 * and the texture one:
3272 * GL_MAX_TEXTURE_COORDS_ARB.
3273 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3274 ******************/
3275 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3276 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3277 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3278 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3279 return WINED3DERR_INVALIDCALL;
3282 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3283 debug_d3dsamplerstate(Type), Type, Value);
3284 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3285 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3286 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3288 /* Handle recording of state blocks */
3289 if (This->isRecordingState) {
3290 TRACE("Recording... not performing anything\n");
3291 return WINED3D_OK;
3294 if(oldValue == Value) {
3295 TRACE("Application is setting the old value over, nothing to do\n");
3296 return WINED3D_OK;
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3301 return WINED3D_OK;
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 /** TODO: check that sampler is in range **/
3307 *Value = This->stateBlock->samplerState[Sampler][Type];
3308 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3310 return WINED3D_OK;
3313 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 RECT windowRect;
3316 UINT winHeight;
3318 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3319 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3320 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3322 winHeight = windowRect.bottom - windowRect.top;
3323 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3324 pRect->right - pRect->left, pRect->bottom - pRect->top);
3325 ENTER_GL();
3326 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3327 checkGLcall("glScissor");
3328 LEAVE_GL();
3330 return WINED3D_OK;
3333 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 GLint scissorBox[4];
3337 ENTER_GL();
3338 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3339 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3340 pRect->left = scissorBox[0];
3341 pRect->top = scissorBox[1];
3342 pRect->right = scissorBox[0] + scissorBox[2];
3343 pRect->bottom = scissorBox[1] + scissorBox[3];
3344 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3345 LEAVE_GL();
3346 return WINED3D_OK;
3349 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3351 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3353 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3355 This->updateStateBlock->vertexDecl = pDecl;
3356 This->updateStateBlock->changed.vertexDecl = TRUE;
3357 This->updateStateBlock->set.vertexDecl = TRUE;
3359 if (This->isRecordingState) {
3360 TRACE("Recording... not performing anything\n");
3363 if (NULL != pDecl) {
3364 IWineD3DVertexDeclaration_AddRef(pDecl);
3366 if (NULL != oldDecl) {
3367 IWineD3DVertexDeclaration_Release(oldDecl);
3369 return WINED3D_OK;
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3377 *ppDecl = This->stateBlock->vertexDecl;
3378 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3379 return WINED3D_OK;
3382 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3386 This->updateStateBlock->vertexShader = pShader;
3387 This->updateStateBlock->changed.vertexShader = TRUE;
3388 This->updateStateBlock->set.vertexShader = TRUE;
3390 if (This->isRecordingState) {
3391 TRACE("Recording... not performing anything\n");
3394 if (NULL != pShader) {
3395 IWineD3DVertexShader_AddRef(pShader);
3397 if (NULL != oldShader) {
3398 IWineD3DVertexShader_Release(oldShader);
3401 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3403 * TODO: merge HAL shaders context switching from prototype
3405 return WINED3D_OK;
3408 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 if (NULL == ppShader) {
3412 return WINED3DERR_INVALIDCALL;
3414 *ppShader = This->stateBlock->vertexShader;
3415 if( NULL != *ppShader)
3416 IWineD3DVertexShader_AddRef(*ppShader);
3418 TRACE("(%p) : returning %p\n", This, *ppShader);
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3423 IWineD3DDevice *iface,
3424 UINT start,
3425 CONST BOOL *srcData,
3426 UINT count) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 int i, cnt = min(count, MAX_CONST_B - start);
3431 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3432 iface, srcData, start, count);
3434 if (srcData == NULL || cnt < 0)
3435 return WINED3DERR_INVALIDCALL;
3437 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3438 for (i = 0; i < cnt; i++)
3439 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3441 for (i = start; i < cnt + start; ++i) {
3442 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3443 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3446 return WINED3D_OK;
3449 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3450 IWineD3DDevice *iface,
3451 UINT start,
3452 BOOL *dstData,
3453 UINT count) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 int cnt = min(count, MAX_CONST_B - start);
3458 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3459 iface, dstData, start, count);
3461 if (dstData == NULL || cnt < 0)
3462 return WINED3DERR_INVALIDCALL;
3464 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3465 return WINED3D_OK;
3468 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3469 IWineD3DDevice *iface,
3470 UINT start,
3471 CONST int *srcData,
3472 UINT count) {
3474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3475 int i, cnt = min(count, MAX_CONST_I - start);
3477 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3478 iface, srcData, start, count);
3480 if (srcData == NULL || cnt < 0)
3481 return WINED3DERR_INVALIDCALL;
3483 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3484 for (i = 0; i < cnt; i++)
3485 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3486 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3488 for (i = start; i < cnt + start; ++i) {
3489 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3490 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3493 return WINED3D_OK;
3496 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3497 IWineD3DDevice *iface,
3498 UINT start,
3499 int *dstData,
3500 UINT count) {
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3503 int cnt = min(count, MAX_CONST_I - start);
3505 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3506 iface, dstData, start, count);
3508 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3509 return WINED3DERR_INVALIDCALL;
3511 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3512 return WINED3D_OK;
3515 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3516 IWineD3DDevice *iface,
3517 UINT start,
3518 CONST float *srcData,
3519 UINT count) {
3521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3522 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3524 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3525 iface, srcData, start, count);
3527 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3528 return WINED3DERR_INVALIDCALL;
3530 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3531 for (i = 0; i < cnt; i++)
3532 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3533 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3535 for (i = start; i < cnt + start; ++i) {
3536 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3537 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3538 ptr->idx = i;
3539 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3540 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3542 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3545 return WINED3D_OK;
3548 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3549 IWineD3DDevice *iface,
3550 UINT start,
3551 float *dstData,
3552 UINT count) {
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3557 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3558 iface, dstData, start, count);
3560 if (dstData == NULL || cnt < 0)
3561 return WINED3DERR_INVALIDCALL;
3563 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3564 return WINED3D_OK;
3567 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3568 DWORD i;
3569 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3574 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3575 DWORD i, tex;
3576 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3577 * it is never called.
3579 * Rules are:
3580 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3581 * that would be really messy and require shader recompilation
3582 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3583 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3584 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3585 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3587 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3588 if(This->oneToOneTexUnitMap) {
3589 TRACE("Not touching 1:1 map\n");
3590 return;
3592 TRACE("Restoring 1:1 texture unit mapping\n");
3593 /* Restore a 1:1 mapping */
3594 for(i = 0; i < MAX_SAMPLERS; i++) {
3595 if(This->texUnitMap[i] != i) {
3596 This->texUnitMap[i] = i;
3597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3598 markTextureStagesDirty(This, i);
3601 This->oneToOneTexUnitMap = TRUE;
3602 return;
3603 } else {
3604 /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
3605 * First, see if we can succeed at all
3607 tex = 0;
3608 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3609 if(This->stateBlock->textures[i] == NULL) tex++;
3612 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3613 FIXME("Too many bound textures to support the combiner settings\n");
3614 return;
3617 /* Now work out the mapping */
3618 tex = 0;
3619 This->oneToOneTexUnitMap = FALSE;
3620 WARN("Non 1:1 mapping UNTESTED!\n");
3621 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3622 /* Skip NULL textures */
3623 if (!This->stateBlock->textures[i]) {
3624 /* Map to -1, so the check below doesn't fail if a non-NULL
3625 * texture is set on this stage */
3626 TRACE("Mapping texture stage %d to -1\n", i);
3627 This->texUnitMap[i] = -1;
3629 continue;
3632 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3633 if(This->texUnitMap[i] != tex) {
3634 This->texUnitMap[i] = tex;
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3636 markTextureStagesDirty(This, i);
3639 ++tex;
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3646 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3647 This->updateStateBlock->pixelShader = pShader;
3648 This->updateStateBlock->changed.pixelShader = TRUE;
3649 This->updateStateBlock->set.pixelShader = TRUE;
3651 /* Handle recording of state blocks */
3652 if (This->isRecordingState) {
3653 TRACE("Recording... not performing anything\n");
3656 if (NULL != pShader) {
3657 IWineD3DPixelShader_AddRef(pShader);
3659 if (NULL != oldShader) {
3660 IWineD3DPixelShader_Release(oldShader);
3663 if (This->isRecordingState) {
3664 TRACE("Recording... not performing anything\n");
3665 return WINED3D_OK;
3668 if(pShader == oldShader) {
3669 TRACE("App is setting the old pixel shader over, nothing to do\n");
3670 return WINED3D_OK;
3673 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3676 /* Rebuild the texture unit mapping if nvrc's are supported */
3677 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3678 IWineD3DDeviceImpl_FindTexUnitMap(This);
3681 return WINED3D_OK;
3684 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 if (NULL == ppShader) {
3688 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3689 return WINED3DERR_INVALIDCALL;
3692 *ppShader = This->stateBlock->pixelShader;
3693 if (NULL != *ppShader) {
3694 IWineD3DPixelShader_AddRef(*ppShader);
3696 TRACE("(%p) : returning %p\n", This, *ppShader);
3697 return WINED3D_OK;
3700 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3701 IWineD3DDevice *iface,
3702 UINT start,
3703 CONST BOOL *srcData,
3704 UINT count) {
3706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3707 int i, cnt = min(count, MAX_CONST_B - start);
3709 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3710 iface, srcData, start, count);
3712 if (srcData == NULL || cnt < 0)
3713 return WINED3DERR_INVALIDCALL;
3715 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3716 for (i = 0; i < cnt; i++)
3717 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3719 for (i = start; i < cnt + start; ++i) {
3720 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3721 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3724 return WINED3D_OK;
3727 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3728 IWineD3DDevice *iface,
3729 UINT start,
3730 BOOL *dstData,
3731 UINT count) {
3733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3734 int cnt = min(count, MAX_CONST_B - start);
3736 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3737 iface, dstData, start, count);
3739 if (dstData == NULL || cnt < 0)
3740 return WINED3DERR_INVALIDCALL;
3742 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3743 return WINED3D_OK;
3746 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3747 IWineD3DDevice *iface,
3748 UINT start,
3749 CONST int *srcData,
3750 UINT count) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 int i, cnt = min(count, MAX_CONST_I - start);
3755 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3756 iface, srcData, start, count);
3758 if (srcData == NULL || cnt < 0)
3759 return WINED3DERR_INVALIDCALL;
3761 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3762 for (i = 0; i < cnt; i++)
3763 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3764 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3766 for (i = start; i < cnt + start; ++i) {
3767 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3768 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3771 return WINED3D_OK;
3774 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3775 IWineD3DDevice *iface,
3776 UINT start,
3777 int *dstData,
3778 UINT count) {
3780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3781 int cnt = min(count, MAX_CONST_I - start);
3783 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3784 iface, dstData, start, count);
3786 if (dstData == NULL || cnt < 0)
3787 return WINED3DERR_INVALIDCALL;
3789 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3790 return WINED3D_OK;
3793 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3794 IWineD3DDevice *iface,
3795 UINT start,
3796 CONST float *srcData,
3797 UINT count) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3800 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3802 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3803 iface, srcData, start, count);
3805 if (srcData == NULL || cnt < 0)
3806 return WINED3DERR_INVALIDCALL;
3808 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3809 for (i = 0; i < cnt; i++)
3810 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3811 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3813 for (i = start; i < cnt + start; ++i) {
3814 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3815 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3816 ptr->idx = i;
3817 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3818 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3820 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3823 return WINED3D_OK;
3826 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3827 IWineD3DDevice *iface,
3828 UINT start,
3829 float *dstData,
3830 UINT count) {
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3835 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3836 iface, dstData, start, count);
3838 if (dstData == NULL || cnt < 0)
3839 return WINED3DERR_INVALIDCALL;
3841 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3842 return WINED3D_OK;
3845 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3846 static HRESULT
3847 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3848 char *dest_ptr, *dest_conv = NULL;
3849 unsigned int i;
3850 DWORD DestFVF = dest->fvf;
3851 WINED3DVIEWPORT vp;
3852 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3853 BOOL doClip;
3854 int numTextures;
3856 if (SrcFVF & WINED3DFVF_NORMAL) {
3857 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3860 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3861 ERR("Source has no position mask\n");
3862 return WINED3DERR_INVALIDCALL;
3865 /* We might access VBOs from this code, so hold the lock */
3866 ENTER_GL();
3868 if (dest->resource.allocatedMemory == NULL) {
3869 /* This may happen if we do direct locking into a vbo. Unlikely,
3870 * but theoretically possible(ddraw processvertices test)
3872 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3873 if(!dest->resource.allocatedMemory) {
3874 LEAVE_GL();
3875 ERR("Out of memory\n");
3876 return E_OUTOFMEMORY;
3878 if(dest->vbo) {
3879 void *src;
3880 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3881 checkGLcall("glBindBufferARB");
3882 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3883 if(src) {
3884 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3886 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3887 checkGLcall("glUnmapBufferARB");
3891 /* Get a pointer into the destination vbo(create one if none exists) and
3892 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3894 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3895 CreateVBO(dest);
3898 if(dest->vbo) {
3899 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3900 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3901 if(!dest_conv) {
3902 ERR("glMapBuffer failed\n");
3903 /* Continue without storing converted vertices */
3907 /* Should I clip?
3908 * a) WINED3DRS_CLIPPING is enabled
3909 * b) WINED3DVOP_CLIP is passed
3911 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3912 static BOOL warned = FALSE;
3914 * The clipping code is not quite correct. Some things need
3915 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3916 * so disable clipping for now.
3917 * (The graphics in Half-Life are broken, and my processvertices
3918 * test crashes with IDirect3DDevice3)
3919 doClip = TRUE;
3921 doClip = FALSE;
3922 if(!warned) {
3923 warned = TRUE;
3924 FIXME("Clipping is broken and disabled for now\n");
3926 } else doClip = FALSE;
3927 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3928 if(dest_conv) {
3929 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3932 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3933 WINED3DTS_VIEW,
3934 &view_mat);
3935 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3936 WINED3DTS_PROJECTION,
3937 &proj_mat);
3938 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3939 WINED3DTS_WORLDMATRIX(0),
3940 &world_mat);
3942 TRACE("View mat:\n");
3943 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); \
3944 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); \
3945 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); \
3946 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); \
3948 TRACE("Proj mat:\n");
3949 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); \
3950 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); \
3951 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); \
3952 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); \
3954 TRACE("World mat:\n");
3955 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); \
3956 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); \
3957 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); \
3958 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); \
3960 /* Get the viewport */
3961 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3962 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3963 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3965 multiply_matrix(&mat,&view_mat,&world_mat);
3966 multiply_matrix(&mat,&proj_mat,&mat);
3968 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3970 for (i = 0; i < dwCount; i+= 1) {
3971 unsigned int tex_index;
3973 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3974 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3975 /* The position first */
3976 float *p =
3977 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3978 float x, y, z, rhw;
3979 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3981 /* Multiplication with world, view and projection matrix */
3982 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);
3983 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);
3984 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);
3985 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);
3987 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3989 /* WARNING: The following things are taken from d3d7 and were not yet checked
3990 * against d3d8 or d3d9!
3993 /* Clipping conditions: From
3994 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3996 * A vertex is clipped if it does not match the following requirements
3997 * -rhw < x <= rhw
3998 * -rhw < y <= rhw
3999 * 0 < z <= rhw
4000 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4002 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4003 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4007 if( !doClip ||
4008 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4009 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4010 ( rhw > eps ) ) ) {
4012 /* "Normal" viewport transformation (not clipped)
4013 * 1) The values are divided by rhw
4014 * 2) The y axis is negative, so multiply it with -1
4015 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4016 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4017 * 4) Multiply x with Width/2 and add Width/2
4018 * 5) The same for the height
4019 * 6) Add the viewpoint X and Y to the 2D coordinates and
4020 * The minimum Z value to z
4021 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4023 * Well, basically it's simply a linear transformation into viewport
4024 * coordinates
4027 x /= rhw;
4028 y /= rhw;
4029 z /= rhw;
4031 y *= -1;
4033 x *= vp.Width / 2;
4034 y *= vp.Height / 2;
4035 z *= vp.MaxZ - vp.MinZ;
4037 x += vp.Width / 2 + vp.X;
4038 y += vp.Height / 2 + vp.Y;
4039 z += vp.MinZ;
4041 rhw = 1 / rhw;
4042 } else {
4043 /* That vertex got clipped
4044 * Contrary to OpenGL it is not dropped completely, it just
4045 * undergoes a different calculation.
4047 TRACE("Vertex got clipped\n");
4048 x += rhw;
4049 y += rhw;
4051 x /= 2;
4052 y /= 2;
4054 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4055 * outside of the main vertex buffer memory. That needs some more
4056 * investigation...
4060 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4063 ( (float *) dest_ptr)[0] = x;
4064 ( (float *) dest_ptr)[1] = y;
4065 ( (float *) dest_ptr)[2] = z;
4066 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4068 dest_ptr += 3 * sizeof(float);
4070 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4071 dest_ptr += sizeof(float);
4074 if(dest_conv) {
4075 float w = 1 / rhw;
4076 ( (float *) dest_conv)[0] = x * w;
4077 ( (float *) dest_conv)[1] = y * w;
4078 ( (float *) dest_conv)[2] = z * w;
4079 ( (float *) dest_conv)[3] = w;
4081 dest_conv += 3 * sizeof(float);
4083 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4084 dest_conv += sizeof(float);
4088 if (DestFVF & WINED3DFVF_PSIZE) {
4089 dest_ptr += sizeof(DWORD);
4090 if(dest_conv) dest_conv += sizeof(DWORD);
4092 if (DestFVF & WINED3DFVF_NORMAL) {
4093 float *normal =
4094 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4095 /* AFAIK this should go into the lighting information */
4096 FIXME("Didn't expect the destination to have a normal\n");
4097 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4098 if(dest_conv) {
4099 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4103 if (DestFVF & WINED3DFVF_DIFFUSE) {
4104 DWORD *color_d =
4105 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4106 if(!color_d) {
4107 static BOOL warned = FALSE;
4109 if(!warned) {
4110 ERR("No diffuse color in source, but destination has one\n");
4111 warned = TRUE;
4114 *( (DWORD *) dest_ptr) = 0xffffffff;
4115 dest_ptr += sizeof(DWORD);
4117 if(dest_conv) {
4118 *( (DWORD *) dest_conv) = 0xffffffff;
4119 dest_conv += sizeof(DWORD);
4122 else {
4123 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4124 if(dest_conv) {
4125 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4126 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4127 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4128 dest_conv += sizeof(DWORD);
4133 if (DestFVF & WINED3DFVF_SPECULAR) {
4134 /* What's the color value in the feedback buffer? */
4135 DWORD *color_s =
4136 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4137 if(!color_s) {
4138 static BOOL warned = FALSE;
4140 if(!warned) {
4141 ERR("No specular color in source, but destination has one\n");
4142 warned = TRUE;
4145 *( (DWORD *) dest_ptr) = 0xFF000000;
4146 dest_ptr += sizeof(DWORD);
4148 if(dest_conv) {
4149 *( (DWORD *) dest_conv) = 0xFF000000;
4150 dest_conv += sizeof(DWORD);
4153 else {
4154 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4155 if(dest_conv) {
4156 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4157 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4158 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4159 dest_conv += sizeof(DWORD);
4164 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4165 float *tex_coord =
4166 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4167 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4168 if(!tex_coord) {
4169 ERR("No source texture, but destination requests one\n");
4170 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4171 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4173 else {
4174 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4175 if(dest_conv) {
4176 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4182 if(dest_conv) {
4183 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4184 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4187 LEAVE_GL();
4189 return WINED3D_OK;
4191 #undef copy_and_next
4193 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4195 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4196 WineDirect3DVertexStridedData strided;
4197 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4199 if (!SrcImpl) {
4200 WARN("NULL source vertex buffer\n");
4201 return WINED3DERR_INVALIDCALL;
4203 /* We don't need the source vbo because this buffer is only used as
4204 * a source for ProcessVertices. Avoid wasting resources by converting the
4205 * buffer and loading the VBO
4207 if(SrcImpl->vbo) {
4208 TRACE("Releasing the source vbo, it won't be needed\n");
4210 if(!SrcImpl->resource.allocatedMemory) {
4211 /* Rescue the data from the buffer */
4212 void *src;
4213 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4214 if(!SrcImpl->resource.allocatedMemory) {
4215 ERR("Out of memory\n");
4216 return E_OUTOFMEMORY;
4219 ENTER_GL();
4220 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4221 checkGLcall("glBindBufferARB");
4223 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4224 if(src) {
4225 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4228 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4229 checkGLcall("glUnmapBufferARB");
4230 } else {
4231 ENTER_GL();
4234 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4235 checkGLcall("glBindBufferARB");
4236 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4237 checkGLcall("glDeleteBuffersARB");
4238 LEAVE_GL();
4240 SrcImpl->vbo = 0;
4243 memset(&strided, 0, sizeof(strided));
4244 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4246 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4249 /*****
4250 * Apply / Get / Set Texture Stage States
4251 * TODO: Verify against dx9 definitions
4252 *****/
4254 /* NOTE: It's expected that this function is going to be called lots of times with the same stage active, so make it the callers responsibility to GLACTIVETEXTURE(Stage) for better state management. Set the correct Texture unit active before calling ApplyTextureStageState */
4255 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4257 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4258 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4260 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4262 /* Check that the stage is within limits */
4263 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
4264 TRACE("Attempt to access invalid texture rejected\n");
4265 return;
4268 ENTER_GL();
4270 switch (Type) {
4271 case WINED3DTSS_ALPHAOP :
4272 case WINED3DTSS_COLOROP :
4273 /* nothing to do as moved to drawprim for now */
4274 break;
4275 case WINED3DTSS_ADDRESSW :
4276 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
4277 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4278 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
4280 } else {
4281 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
4282 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
4283 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
4284 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
4286 #endif
4287 case WINED3DTSS_TEXCOORDINDEX :
4289 /* Handled from the state table */
4291 break;
4293 /* Unhandled */
4294 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4295 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU);
4296 break;
4298 case WINED3DTSS_BUMPENVMAT00 :
4299 case WINED3DTSS_BUMPENVMAT01 :
4300 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4301 break;
4302 case WINED3DTSS_BUMPENVMAT10 :
4303 case WINED3DTSS_BUMPENVMAT11 :
4304 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4305 break;
4307 case WINED3DTSS_BUMPENVLSCALE :
4308 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4309 break;
4311 case WINED3DTSS_BUMPENVLOFFSET :
4312 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4313 break;
4315 case WINED3DTSS_RESULTARG :
4316 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4317 break;
4319 default:
4320 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
4321 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4324 LEAVE_GL();
4326 return;
4329 /*****
4330 * Get / Set Texture Stage States
4331 * TODO: Verify against dx9 definitions
4332 *****/
4333 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4337 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4339 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4341 /* Reject invalid texture units */
4342 if (Stage >= GL_LIMITS(texture_stages)) {
4343 TRACE("Attempt to access invalid texture rejected\n");
4344 return WINED3DERR_INVALIDCALL;
4347 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4348 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4349 This->updateStateBlock->textureState[Stage][Type] = Value;
4351 if (This->isRecordingState) {
4352 TRACE("Recording... not performing anything\n");
4353 return WINED3D_OK;
4356 /* Checked after the assignments to allow proper stateblock recording */
4357 if(oldValue == Value) {
4358 TRACE("App is setting the old value over, nothing to do\n");
4359 return WINED3D_OK;
4362 if(Stage > This->stateBlock->lowest_disabled_stage &&
4363 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4364 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4365 * Changes in other states are important on disabled stages too
4367 return WINED3D_OK;
4370 if(Type == WINED3DTSS_COLOROP) {
4371 int i;
4373 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4374 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4375 * they have to be disabled
4377 * The current stage is dirtified below.
4379 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4380 TRACE("Additionally dirtifying stage %d\n", i);
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4383 This->stateBlock->lowest_disabled_stage = Stage;
4384 TRACE("New lowest disabled: %d\n", Stage);
4385 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4386 /* Previously disabled stage enabled. Stages above it may need enabling
4387 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4388 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4390 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4393 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4394 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4395 break;
4397 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4400 This->stateBlock->lowest_disabled_stage = i;
4401 TRACE("New lowest disabled: %d\n", i);
4403 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4404 /* TODO: Built a stage -> texture unit mapping for register combiners */
4408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4410 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4411 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4412 * will call FindTexUnitMap too.
4414 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4415 IWineD3DDeviceImpl_FindTexUnitMap(This);
4417 return WINED3D_OK;
4420 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4422 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4423 *pValue = This->updateStateBlock->textureState[Stage][Type];
4424 return WINED3D_OK;
4427 /*****
4428 * Get / Set Texture
4429 *****/
4430 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4433 IWineD3DBaseTexture *oldTexture;
4435 oldTexture = This->updateStateBlock->textures[Stage];
4436 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4438 #if 0 /* TODO: check so vertex textures */
4439 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4440 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4441 return WINED3D_OK;
4443 #endif
4445 /* Reject invalid texture units */
4446 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4447 WARN("Attempt to access invalid texture rejected\n");
4448 return WINED3DERR_INVALIDCALL;
4451 if(pTexture != NULL) {
4452 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4454 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4455 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4456 return WINED3DERR_INVALIDCALL;
4458 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4461 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4462 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4464 This->updateStateBlock->set.textures[Stage] = TRUE;
4465 This->updateStateBlock->changed.textures[Stage] = TRUE;
4466 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4467 This->updateStateBlock->textures[Stage] = pTexture;
4469 /* Handle recording of state blocks */
4470 if (This->isRecordingState) {
4471 TRACE("Recording... not performing anything\n");
4472 return WINED3D_OK;
4475 if(oldTexture == pTexture) {
4476 TRACE("App is setting the same texture again, nothing to do\n");
4477 return WINED3D_OK;
4480 /** NOTE: MSDN says that setTexture increases the reference count,
4481 * and the the application nust set the texture back to null (or have a leaky application),
4482 * This means we should pass the refcount up to the parent
4483 *******************************/
4484 if (NULL != This->updateStateBlock->textures[Stage]) {
4485 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4486 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4488 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4489 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4490 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4491 * so the COLOROP and ALPHAOP have to be dirtified.
4493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4496 if(bindCount == 1) {
4497 new->baseTexture.sampler = Stage;
4499 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4503 if (NULL != oldTexture) {
4504 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4505 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4507 IWineD3DBaseTexture_Release(oldTexture);
4508 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4513 if(bindCount && old->baseTexture.sampler == Stage) {
4514 int i;
4515 /* Have to do a search for the other sampler(s) where the texture is bound to
4516 * Shouldn't happen as long as apps bind a texture only to one stage
4518 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4519 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4520 if(This->updateStateBlock->textures[i] == oldTexture) {
4521 old->baseTexture.sampler = i;
4522 break;
4528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4530 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4531 * pixel shader is used
4533 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4534 IWineD3DDeviceImpl_FindTexUnitMap(This);
4537 return WINED3D_OK;
4540 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4544 /* Reject invalid texture units */
4545 if (Stage >= GL_LIMITS(sampler_stages)) {
4546 TRACE("Attempt to access invalid texture rejected\n");
4547 return WINED3DERR_INVALIDCALL;
4549 *ppTexture=This->stateBlock->textures[Stage];
4550 if (*ppTexture)
4551 IWineD3DBaseTexture_AddRef(*ppTexture);
4553 return WINED3D_OK;
4556 /*****
4557 * Get Back Buffer
4558 *****/
4559 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4560 IWineD3DSurface **ppBackBuffer) {
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 IWineD3DSwapChain *swapChain;
4563 HRESULT hr;
4565 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4567 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4568 if (hr == WINED3D_OK) {
4569 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4570 IWineD3DSwapChain_Release(swapChain);
4571 } else {
4572 *ppBackBuffer = NULL;
4574 return hr;
4577 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 WARN("(%p) : stub, calling idirect3d for now\n", This);
4580 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4583 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 IWineD3DSwapChain *swapChain;
4586 HRESULT hr;
4588 if(iSwapChain > 0) {
4589 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4590 if (hr == WINED3D_OK) {
4591 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4592 IWineD3DSwapChain_Release(swapChain);
4593 } else {
4594 FIXME("(%p) Error getting display mode\n", This);
4596 } else {
4597 /* Don't read the real display mode,
4598 but return the stored mode instead. X11 can't change the color
4599 depth, and some apps are pretty angry if they SetDisplayMode from
4600 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4602 Also don't relay to the swapchain because with ddraw it's possible
4603 that there isn't a swapchain at all */
4604 pMode->Width = This->ddraw_width;
4605 pMode->Height = This->ddraw_height;
4606 pMode->Format = This->ddraw_format;
4607 pMode->RefreshRate = 0;
4608 hr = WINED3D_OK;
4611 return hr;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("(%p)->(%p)\n", This, hWnd);
4618 This->ddraw_window = hWnd;
4619 return WINED3D_OK;
4622 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 TRACE("(%p)->(%p)\n", This, hWnd);
4626 *hWnd = This->ddraw_window;
4627 return WINED3D_OK;
4630 /*****
4631 * Stateblock related functions
4632 *****/
4634 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4636 IWineD3DStateBlockImpl *object;
4637 HRESULT temp_result;
4639 TRACE("(%p)\n", This);
4641 if (This->isRecordingState) {
4642 return WINED3DERR_INVALIDCALL;
4645 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4646 if (NULL == object ) {
4647 FIXME("(%p)Error allocating memory for stateblock\n", This);
4648 return E_OUTOFMEMORY;
4650 TRACE("(%p) created object %p\n", This, object);
4651 object->wineD3DDevice= This;
4652 /** FIXME: object->parent = parent; **/
4653 object->parent = NULL;
4654 object->blockType = WINED3DSBT_ALL;
4655 object->ref = 1;
4656 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4658 temp_result = allocate_shader_constants(object);
4659 if (WINED3D_OK != temp_result)
4660 return temp_result;
4662 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4663 This->updateStateBlock = object;
4664 This->isRecordingState = TRUE;
4666 TRACE("(%p) recording stateblock %p\n",This , object);
4667 return WINED3D_OK;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 if (!This->isRecordingState) {
4674 FIXME("(%p) not recording! returning error\n", This);
4675 *ppStateBlock = NULL;
4676 return WINED3DERR_INVALIDCALL;
4679 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4680 This->isRecordingState = FALSE;
4681 This->updateStateBlock = This->stateBlock;
4682 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4683 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4684 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4685 return WINED3D_OK;
4688 /*****
4689 * Scene related functions
4690 *****/
4691 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4692 /* At the moment we have no need for any functionality at the beginning
4693 of a scene */
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 TRACE("(%p) : stub\n", This);
4696 return WINED3D_OK;
4699 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4701 TRACE("(%p)\n", This);
4702 ENTER_GL();
4703 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4704 glFlush();
4705 checkGLcall("glFlush");
4707 TRACE("End Scene\n");
4708 /* If we're using FBOs this isn't needed */
4709 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4711 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4712 IUnknown *targetContainer = NULL;
4713 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4714 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4715 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4716 /** always dirtify for now. we must find a better way to see that surface have been modified
4717 (Modifications should will only occur via draw-primitive, but we do need better locking
4718 switching to render-to-texture should remove the overhead though.
4720 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4721 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4722 IWineD3DSurface_PreLoad(This->render_targets[0]);
4723 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4724 IUnknown_Release(targetContainer);
4727 This->sceneEnded = TRUE;
4728 LEAVE_GL();
4729 return WINED3D_OK;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4733 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4734 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4736 IWineD3DSwapChain *swapChain = NULL;
4737 int i;
4738 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4740 TRACE("(%p) Presenting the frame\n", This);
4742 for(i = 0 ; i < swapchains ; i ++) {
4744 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4745 TRACE("presentinng chain %d, %p\n", i, swapChain);
4746 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4747 IWineD3DSwapChain_Release(swapChain);
4750 return WINED3D_OK;
4753 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4754 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4758 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4759 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4760 GLbitfield glMask = 0;
4761 GLboolean old_ztest;
4762 GLfloat old_z_clear_value;
4763 GLint old_stencil_clear_value;
4764 GLfloat old_color_clear_value[4];
4765 unsigned int i;
4766 CONST WINED3DRECT* curRect;
4768 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4769 Count, pRects, Flags, Z, Stencil);
4771 ENTER_GL();
4773 glEnable(GL_SCISSOR_TEST);
4774 checkGLcall("glEnable GL_SCISSOR_TEST");
4776 if (Count > 0 && pRects) {
4777 curRect = pRects;
4778 } else {
4779 curRect = NULL;
4782 /* Only set the values up once, as they are not changing */
4783 if (Flags & WINED3DCLEAR_STENCIL) {
4784 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4785 glClearStencil(Stencil);
4786 checkGLcall("glClearStencil");
4787 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4788 glStencilMask(0xFFFFFFFF);
4791 if (Flags & WINED3DCLEAR_ZBUFFER) {
4792 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4793 glDepthMask(GL_TRUE);
4794 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4795 glClearDepth(Z);
4796 checkGLcall("glClearDepth");
4797 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4800 if (Flags & WINED3DCLEAR_TARGET) {
4801 TRACE("Clearing screen with glClear to color %x\n", Color);
4802 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4803 glClearColor(D3DCOLOR_R(Color),
4804 D3DCOLOR_G(Color),
4805 D3DCOLOR_B(Color),
4806 D3DCOLOR_A(Color));
4807 checkGLcall("glClearColor");
4809 /* Clear ALL colors! */
4810 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4811 glMask = glMask | GL_COLOR_BUFFER_BIT;
4814 /* Now process each rect in turn */
4815 for (i = 0; i < Count || i == 0; i++) {
4817 if (curRect) {
4818 /* Note gl uses lower left, width/height */
4819 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4820 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4821 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4822 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4823 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4824 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4825 checkGLcall("glScissor");
4826 } else {
4827 glScissor(This->stateBlock->viewport.X,
4828 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4829 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4830 This->stateBlock->viewport.Width,
4831 This->stateBlock->viewport.Height);
4832 checkGLcall("glScissor");
4835 /* Clear the selected rectangle (or full screen) */
4836 glClear(glMask);
4837 checkGLcall("glClear");
4839 /* Step to the next rectangle */
4840 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4843 /* Restore the old values (why..?) */
4844 if (Flags & WINED3DCLEAR_STENCIL) {
4845 glClearStencil(old_stencil_clear_value);
4846 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4848 if (Flags & WINED3DCLEAR_ZBUFFER) {
4849 glDepthMask(old_ztest);
4850 glClearDepth(old_z_clear_value);
4852 if (Flags & WINED3DCLEAR_TARGET) {
4853 glClearColor(old_color_clear_value[0],
4854 old_color_clear_value[1],
4855 old_color_clear_value[2],
4856 old_color_clear_value[3]);
4857 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4858 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4859 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4860 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4863 glDisable(GL_SCISSOR_TEST);
4864 checkGLcall("glDisable");
4865 LEAVE_GL();
4867 return WINED3D_OK;
4870 /*****
4871 * Drawing functions
4872 *****/
4873 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4874 UINT PrimitiveCount) {
4876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4877 This->stateBlock->streamIsUP = FALSE;
4879 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4880 debug_d3dprimitivetype(PrimitiveType),
4881 StartVertex, PrimitiveCount);
4882 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4883 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
4886 return WINED3D_OK;
4889 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4890 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4891 WINED3DPRIMITIVETYPE PrimitiveType,
4892 INT baseVIndex, UINT minIndex,
4893 UINT NumVertices, UINT startIndex, UINT primCount) {
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4896 UINT idxStride = 2;
4897 IWineD3DIndexBuffer *pIB;
4898 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4900 pIB = This->stateBlock->pIndexData;
4901 This->stateBlock->streamIsUP = FALSE;
4903 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
4904 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4905 minIndex, NumVertices, startIndex, baseVIndex, primCount);
4907 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4908 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4909 idxStride = 2;
4910 } else {
4911 idxStride = 4;
4914 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
4915 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
4917 return WINED3D_OK;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4921 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4922 UINT VertexStreamZeroStride) {
4923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4926 debug_d3dprimitivetype(PrimitiveType),
4927 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4929 /* release the stream source */
4930 if (This->stateBlock->streamSource[0] != NULL) {
4931 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4934 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4935 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4936 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4937 This->stateBlock->streamIsUP = TRUE;
4939 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4940 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
4942 /* MSDN specifies stream zero settings must be set to NULL */
4943 This->stateBlock->streamStride[0] = 0;
4944 This->stateBlock->streamSource[0] = NULL;
4946 /*stream zero settings set to null at end, as per the msdn */
4947 return WINED3D_OK;
4950 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4951 UINT MinVertexIndex, UINT NumVertices,
4952 UINT PrimitiveCount, CONST void* pIndexData,
4953 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4954 UINT VertexStreamZeroStride) {
4955 int idxStride;
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4959 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4960 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4961 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4963 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4964 idxStride = 2;
4965 } else {
4966 idxStride = 4;
4969 /* release the stream and index data */
4970 if (This->stateBlock->streamSource[0] != NULL) {
4971 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4973 if (This->stateBlock->pIndexData) {
4974 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
4977 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4978 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4979 This->stateBlock->streamIsUP = TRUE;
4980 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4982 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
4984 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4985 This->stateBlock->streamSource[0] = NULL;
4986 This->stateBlock->streamStride[0] = 0;
4987 This->stateBlock->pIndexData = NULL;
4989 return WINED3D_OK;
4992 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4994 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
4995 return WINED3D_OK;
4997 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4998 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5000 HRESULT hr = WINED3D_OK;
5001 WINED3DRESOURCETYPE sourceType;
5002 WINED3DRESOURCETYPE destinationType;
5003 int i ,levels;
5005 /* TODO: think about moving the code into IWineD3DBaseTexture */
5007 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5009 /* verify that the source and destination textures aren't NULL */
5010 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5011 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5012 This, pSourceTexture, pDestinationTexture);
5013 hr = WINED3DERR_INVALIDCALL;
5016 if (pSourceTexture == pDestinationTexture) {
5017 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5018 This, pSourceTexture, pDestinationTexture);
5019 hr = WINED3DERR_INVALIDCALL;
5021 /* Verify that the source and destination textures are the same type */
5022 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5023 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5025 if (sourceType != destinationType) {
5026 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5027 This);
5028 hr = WINED3DERR_INVALIDCALL;
5031 /* check that both textures have the identical numbers of levels */
5032 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5033 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5034 hr = WINED3DERR_INVALIDCALL;
5037 if (WINED3D_OK == hr) {
5039 /* Make sure that the destination texture is loaded */
5040 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5042 /* Update every surface level of the texture */
5043 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5045 switch (sourceType) {
5046 case WINED3DRTYPE_TEXTURE:
5048 IWineD3DSurface *srcSurface;
5049 IWineD3DSurface *destSurface;
5051 for (i = 0 ; i < levels ; ++i) {
5052 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5053 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5054 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5055 IWineD3DSurface_Release(srcSurface);
5056 IWineD3DSurface_Release(destSurface);
5057 if (WINED3D_OK != hr) {
5058 WARN("(%p) : Call to update surface failed\n", This);
5059 return hr;
5063 break;
5064 case WINED3DRTYPE_CUBETEXTURE:
5066 IWineD3DSurface *srcSurface;
5067 IWineD3DSurface *destSurface;
5068 WINED3DCUBEMAP_FACES faceType;
5070 for (i = 0 ; i < levels ; ++i) {
5071 /* Update each cube face */
5072 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5073 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5074 if (WINED3D_OK != hr) {
5075 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5076 } else {
5077 TRACE("Got srcSurface %p\n", srcSurface);
5079 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5080 if (WINED3D_OK != hr) {
5081 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5082 } else {
5083 TRACE("Got desrSurface %p\n", destSurface);
5085 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5086 IWineD3DSurface_Release(srcSurface);
5087 IWineD3DSurface_Release(destSurface);
5088 if (WINED3D_OK != hr) {
5089 WARN("(%p) : Call to update surface failed\n", This);
5090 return hr;
5095 break;
5096 #if 0 /* TODO: Add support for volume textures */
5097 case WINED3DRTYPE_VOLUMETEXTURE:
5099 IWineD3DVolume srcVolume = NULL;
5100 IWineD3DSurface destVolume = NULL;
5102 for (i = 0 ; i < levels ; ++i) {
5103 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5104 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5105 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5106 IWineD3DVolume_Release(srcSurface);
5107 IWineD3DVolume_Release(destSurface);
5108 if (WINED3D_OK != hr) {
5109 WARN("(%p) : Call to update volume failed\n", This);
5110 return hr;
5114 break;
5115 #endif
5116 default:
5117 FIXME("(%p) : Unsupported source and destination type\n", This);
5118 hr = WINED3DERR_INVALIDCALL;
5122 return hr;
5125 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5126 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5127 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 TRACE("(%p) : stub\n", This);
5131 return WINED3D_OK;
5133 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5136 * NOTE It may be best to move the code into surface to occomplish this
5137 ****************************************/
5139 WINED3DSURFACE_DESC surfaceDesc;
5140 unsigned int surfaceWidth, surfaceHeight;
5141 glDescriptor *targetGlDescription = NULL;
5142 glDescriptor *surfaceGlDescription = NULL;
5143 IWineD3DSwapChainImpl *container = NULL;
5145 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5146 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5147 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5149 surfaceDesc.Width = &surfaceWidth;
5150 surfaceDesc.Height = &surfaceHeight;
5151 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5152 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5154 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5155 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5156 ENTER_GL();
5157 /* TODO: opengl Context switching for swapchains etc... */
5158 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
5159 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
5160 glReadBuffer(GL_BACK);
5161 vcheckGLcall("glReadBuffer(GL_BACK)");
5162 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
5163 glReadBuffer(GL_FRONT);
5164 vcheckGLcall("glReadBuffer(GL_FRONT)");
5165 } else if (pRenderTarget == This->depthStencilBuffer) {
5166 FIXME("Reading of depthstencil not yet supported\n");
5169 glReadPixels(0,
5171 surfaceWidth,
5172 surfaceHeight,
5173 surfaceGlDescription->glFormat,
5174 surfaceGlDescription->glType,
5175 (void *)IWineD3DSurface_GetData(pSurface));
5176 vcheckGLcall("glReadPixels(...)");
5177 if(NULL != container ){
5178 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5180 } else {
5181 IWineD3DBaseTexture *container;
5182 GLenum textureDimensions = GL_TEXTURE_2D;
5184 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5185 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5186 IWineD3DBaseTexture_Release(container);
5188 /* TODO: 2D -> Cube surface coppies etc.. */
5189 if (surfaceGlDescription->target != textureDimensions) {
5190 FIXME("(%p) : Texture dimension mismatch\n", This);
5192 glEnable(textureDimensions);
5193 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5194 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5195 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5196 vcheckGLcall("glBindTexture");
5197 glGetTexImage(surfaceGlDescription->target,
5198 surfaceGlDescription->level,
5199 surfaceGlDescription->glFormat,
5200 surfaceGlDescription->glType,
5201 (void *)IWineD3DSurface_GetData(pSurface));
5202 glDisable(textureDimensions);
5203 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5206 LEAVE_GL();
5207 return WINED3D_OK;
5210 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5211 IWineD3DSwapChain *swapChain;
5212 HRESULT hr;
5213 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5214 if(hr == WINED3D_OK) {
5215 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5216 IWineD3DSwapChain_Release(swapChain);
5218 return hr;
5221 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 /* return a sensible default */
5224 *pNumPasses = 1;
5225 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5226 FIXME("(%p) : stub\n", This);
5227 return WINED3D_OK;
5230 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 int j;
5233 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5234 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5235 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5236 return WINED3DERR_INVALIDCALL;
5238 for (j = 0; j < 256; ++j) {
5239 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5240 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5241 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5242 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5244 TRACE("(%p) : returning\n", This);
5245 return WINED3D_OK;
5248 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 int j;
5251 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5252 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5253 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5254 return WINED3DERR_INVALIDCALL;
5256 for (j = 0; j < 256; ++j) {
5257 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5258 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5259 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5260 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5262 TRACE("(%p) : returning\n", This);
5263 return WINED3D_OK;
5266 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5268 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5269 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5270 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5271 return WINED3DERR_INVALIDCALL;
5273 /*TODO: stateblocks */
5274 This->currentPalette = PaletteNumber;
5275 TRACE("(%p) : returning\n", This);
5276 return WINED3D_OK;
5279 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5281 if (PaletteNumber == NULL) {
5282 WARN("(%p) : returning Invalid Call\n", This);
5283 return WINED3DERR_INVALIDCALL;
5285 /*TODO: stateblocks */
5286 *PaletteNumber = This->currentPalette;
5287 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5288 return WINED3D_OK;
5291 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 static BOOL showFixmes = TRUE;
5294 if (showFixmes) {
5295 FIXME("(%p) : stub\n", This);
5296 showFixmes = FALSE;
5299 This->softwareVertexProcessing = bSoftware;
5300 return WINED3D_OK;
5304 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5306 static BOOL showFixmes = TRUE;
5307 if (showFixmes) {
5308 FIXME("(%p) : stub\n", This);
5309 showFixmes = FALSE;
5311 return This->softwareVertexProcessing;
5315 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 IWineD3DSwapChain *swapChain;
5318 HRESULT hr;
5320 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5322 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5323 if(hr == WINED3D_OK){
5324 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5325 IWineD3DSwapChain_Release(swapChain);
5326 }else{
5327 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5329 return hr;
5333 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 static BOOL showfixmes = TRUE;
5336 if(nSegments != 0.0f) {
5337 if( showfixmes) {
5338 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5339 showfixmes = FALSE;
5342 return WINED3D_OK;
5345 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5347 static BOOL showfixmes = TRUE;
5348 if( showfixmes) {
5349 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5350 showfixmes = FALSE;
5352 return 0.0f;
5355 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5357 /** TODO: remove casts to IWineD3DSurfaceImpl
5358 * NOTE: move code to surface to accomplish this
5359 ****************************************/
5360 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5361 int srcWidth, srcHeight;
5362 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5363 WINED3DFORMAT destFormat, srcFormat;
5364 UINT destSize;
5365 int destLeft, destTop;
5366 WINED3DPOOL srcPool, destPool;
5367 int offset = 0;
5368 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5369 glDescriptor *glDescription = NULL;
5370 GLenum textureDimensions = GL_TEXTURE_2D;
5371 IWineD3DBaseTexture *baseTexture;
5373 WINED3DSURFACE_DESC winedesc;
5375 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5376 memset(&winedesc, 0, sizeof(winedesc));
5377 winedesc.Width = &srcSurfaceWidth;
5378 winedesc.Height = &srcSurfaceHeight;
5379 winedesc.Pool = &srcPool;
5380 winedesc.Format = &srcFormat;
5382 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5384 winedesc.Width = &destSurfaceWidth;
5385 winedesc.Height = &destSurfaceHeight;
5386 winedesc.Pool = &destPool;
5387 winedesc.Format = &destFormat;
5388 winedesc.Size = &destSize;
5390 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5392 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5393 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5394 return WINED3DERR_INVALIDCALL;
5397 if (destFormat == WINED3DFMT_UNKNOWN) {
5398 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5399 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5401 /* Get the update surface description */
5402 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5405 /* Make sure the surface is loaded and up to date */
5406 IWineD3DSurface_PreLoad(pDestinationSurface);
5408 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5410 ENTER_GL();
5412 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5413 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5414 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5415 destLeft = pDestPoint ? pDestPoint->x : 0;
5416 destTop = pDestPoint ? pDestPoint->y : 0;
5419 /* This function doesn't support compressed textures
5420 the pitch is just bytesPerPixel * width */
5421 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5422 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5423 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5424 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5426 /* TODO DXT formats */
5428 if(pSourceRect != NULL && pSourceRect->top != 0){
5429 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5431 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5432 ,This
5433 ,glDescription->level
5434 ,destLeft
5435 ,destTop
5436 ,srcWidth
5437 ,srcHeight
5438 ,glDescription->glFormat
5439 ,glDescription->glType
5440 ,IWineD3DSurface_GetData(pSourceSurface)
5443 /* Sanity check */
5444 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5446 /* need to lock the surface to get the data */
5447 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5450 /* TODO: Cube and volume support */
5451 if(rowoffset != 0){
5452 /* not a whole row so we have to do it a line at a time */
5453 int j;
5455 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5456 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5458 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5460 glTexSubImage2D(glDescription->target
5461 ,glDescription->level
5462 ,destLeft
5464 ,srcWidth
5466 ,glDescription->glFormat
5467 ,glDescription->glType
5468 ,data /* could be quicker using */
5470 data += rowoffset;
5473 } else { /* Full width, so just write out the whole texture */
5475 if (WINED3DFMT_DXT1 == destFormat ||
5476 WINED3DFMT_DXT2 == destFormat ||
5477 WINED3DFMT_DXT3 == destFormat ||
5478 WINED3DFMT_DXT4 == destFormat ||
5479 WINED3DFMT_DXT5 == destFormat) {
5480 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5481 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5482 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5483 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5484 } if (destFormat != srcFormat) {
5485 FIXME("Updating mixed format compressed texture is not curretly support\n");
5486 } else {
5487 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5488 glDescription->level,
5489 glDescription->glFormatInternal,
5490 srcWidth,
5491 srcHeight,
5493 destSize,
5494 IWineD3DSurface_GetData(pSourceSurface));
5496 } else {
5497 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5501 } else {
5502 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5504 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5505 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5506 data returned by GetData non-power2 width/height with hardware non-power2
5507 pow2Width/height are set to surface width height, repacking isn't needed so it
5508 doesn't matter which function gets called. */
5509 glTexSubImage2D(glDescription->target
5510 ,glDescription->level
5511 ,destLeft
5512 ,destTop
5513 ,srcWidth
5514 ,srcHeight
5515 ,glDescription->glFormat
5516 ,glDescription->glType
5517 ,IWineD3DSurface_GetData(pSourceSurface)
5519 } else {
5521 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5522 glTexSubImage2D(glDescription->target
5523 ,glDescription->level
5524 ,destLeft
5525 ,destTop
5526 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5527 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5528 ,glDescription->glFormat
5529 ,glDescription->glType
5530 ,IWineD3DSurface_GetData(pSourceSurface)
5536 checkGLcall("glTexSubImage2D");
5537 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5539 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5540 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5541 * surface bigger than it needs to be hmm.. */
5542 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5543 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5544 IWineD3DBaseTexture_Release(baseTexture);
5547 glDisable(textureDimensions); /* This needs to be managed better.... */
5548 LEAVE_GL();
5550 return WINED3D_OK;
5553 /* Implementation details at http://developer.nvidia.com/attach/6494
5555 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5556 hmm.. no longer supported use
5557 OpenGL evaluators or tessellate surfaces within your application.
5560 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5561 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5564 FIXME("(%p) : Stub\n", This);
5565 return WINED3D_OK;
5569 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5570 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5572 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5573 FIXME("(%p) : Stub\n", This);
5574 return WINED3D_OK;
5577 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5579 TRACE("(%p) Handle(%d)\n", This, Handle);
5580 FIXME("(%p) : Stub\n", This);
5581 return WINED3D_OK;
5584 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5586 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5587 DDBLTFX BltFx;
5588 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5590 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5591 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5592 return WINED3DERR_INVALIDCALL;
5595 /* Just forward this to the DirectDraw blitting engine */
5596 memset(&BltFx, 0, sizeof(BltFx));
5597 BltFx.dwSize = sizeof(BltFx);
5598 BltFx.u5.dwFillColor = color;
5599 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5602 /* rendertarget and deptth stencil functions */
5603 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5606 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5607 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5608 return WINED3DERR_INVALIDCALL;
5611 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5612 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5613 /* Note inc ref on returned surface */
5614 if(*ppRenderTarget != NULL)
5615 IWineD3DSurface_AddRef(*ppRenderTarget);
5616 return WINED3D_OK;
5619 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5621 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5622 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5623 IWineD3DSwapChainImpl *Swapchain;
5624 HRESULT hr;
5626 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5628 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5629 if(hr != WINED3D_OK) {
5630 ERR("Can't get the swapchain\n");
5631 return hr;
5634 /* Make sure to release the swapchain */
5635 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5637 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5638 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5639 return WINED3DERR_INVALIDCALL;
5641 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5642 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5643 return WINED3DERR_INVALIDCALL;
5646 if(Swapchain->frontBuffer != Front) {
5647 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5649 if(Swapchain->frontBuffer)
5650 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5651 Swapchain->frontBuffer = Front;
5653 if(Swapchain->frontBuffer) {
5654 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5658 if(Back && !Swapchain->backBuffer) {
5659 /* We need memory for the back buffer array - only one back buffer this way */
5660 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5661 if(!Swapchain->backBuffer) {
5662 ERR("Out of memory\n");
5663 return E_OUTOFMEMORY;
5667 if(Swapchain->backBuffer[0] != Back) {
5668 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5669 ENTER_GL();
5670 if(!Swapchain->backBuffer[0]) {
5671 /* GL was told to draw to the front buffer at creation,
5672 * undo that
5674 glDrawBuffer(GL_BACK);
5675 checkGLcall("glDrawBuffer(GL_BACK)");
5676 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5677 Swapchain->presentParms.BackBufferCount = 1;
5678 } else if (!Back) {
5679 /* That makes problems - disable for now */
5680 /* glDrawBuffer(GL_FRONT); */
5681 checkGLcall("glDrawBuffer(GL_FRONT)");
5682 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5683 Swapchain->presentParms.BackBufferCount = 0;
5685 LEAVE_GL();
5687 if(Swapchain->backBuffer[0])
5688 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5689 Swapchain->backBuffer[0] = Back;
5691 if(Swapchain->backBuffer[0]) {
5692 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5693 } else {
5694 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5699 return WINED3D_OK;
5702 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 *ppZStencilSurface = This->depthStencilBuffer;
5705 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5707 if(*ppZStencilSurface != NULL) {
5708 /* Note inc ref on returned surface */
5709 IWineD3DSurface_AddRef(*ppZStencilSurface);
5711 return WINED3D_OK;
5714 static void bind_fbo(IWineD3DDevice *iface) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5717 if (!This->fbo) {
5718 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5719 checkGLcall("glGenFramebuffersEXT()");
5721 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5722 checkGLcall("glBindFramebuffer()");
5725 /* TODO: Handle stencil attachments */
5726 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5730 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5732 bind_fbo(iface);
5734 if (depth_stencil_impl) {
5735 GLenum texttarget, target;
5736 GLint old_binding = 0;
5738 IWineD3DSurface_PreLoad(depth_stencil);
5739 texttarget = depth_stencil_impl->glDescription.target;
5740 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5742 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5743 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5744 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5745 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5746 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5747 glBindTexture(target, old_binding);
5749 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5750 checkGLcall("glFramebufferTexture2DEXT()");
5751 } else {
5752 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5753 checkGLcall("glFramebufferTexture2DEXT()");
5756 if (!This->render_offscreen) {
5757 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5758 checkGLcall("glBindFramebuffer()");
5762 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5766 if (idx >= GL_LIMITS(buffers)) {
5767 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5770 bind_fbo(iface);
5772 if (rtimpl) {
5773 GLenum texttarget, target;
5774 GLint old_binding = 0;
5776 IWineD3DSurface_PreLoad(render_target);
5777 texttarget = rtimpl->glDescription.target;
5778 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5780 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5781 glBindTexture(target, rtimpl->glDescription.textureName);
5782 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5783 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5784 glBindTexture(target, old_binding);
5786 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5787 checkGLcall("glFramebufferTexture2DEXT()");
5789 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5790 } else {
5791 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5792 checkGLcall("glFramebufferTexture2DEXT()");
5794 This->draw_buffers[idx] = GL_NONE;
5797 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5798 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5799 checkGLcall("glDrawBuffers()");
5802 if (!This->render_offscreen) {
5803 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5804 checkGLcall("glBindFramebuffer()");
5808 /* internal static helper functions */
5809 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5810 IWineD3DSurface *RenderSurface);
5812 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5814 HRESULT hr = WINED3D_OK;
5815 WINED3DVIEWPORT viewport;
5817 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5819 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5820 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5821 return WINED3DERR_INVALIDCALL;
5824 /* MSDN says that null disables the render target
5825 but a device must always be associated with a render target
5826 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5828 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5829 for more details
5831 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5832 FIXME("Trying to set render target 0 to NULL\n");
5833 return WINED3DERR_INVALIDCALL;
5835 /* TODO: replace Impl* usage with interface usage */
5836 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5837 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);
5838 return WINED3DERR_INVALIDCALL;
5840 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5841 * builds, but I think wine counts as a 'debug' build for now.
5842 ******************************/
5843 /* If we are trying to set what we already have, don't bother */
5844 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5845 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5846 } else {
5847 /* Otherwise, set the render target up */
5849 if (!This->sceneEnded) {
5850 IWineD3DDevice_EndScene(iface);
5852 TRACE("clearing renderer\n");
5853 /* IWineD3DDeviceImpl_CleanRender(iface); */
5854 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5855 depending on the renter target implementation being used.
5856 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5857 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5858 stencil buffer and incure an extra memory overhead */
5859 if (RenderTargetIndex == 0) {
5860 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5861 } else {
5862 hr = WINED3D_OK;
5865 /* Replace the render target */
5866 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5867 This->render_targets[RenderTargetIndex] = pRenderTarget;
5868 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5870 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5871 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5875 if (SUCCEEDED(hr)) {
5876 /* Finally, reset the viewport as the MSDN states. */
5877 /* TODO: Replace impl usage */
5878 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5879 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5880 viewport.X = 0;
5881 viewport.Y = 0;
5882 viewport.MaxZ = 1.0f;
5883 viewport.MinZ = 0.0f;
5884 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5885 } else {
5886 FIXME("Unknown error setting the render target\n");
5888 This->sceneEnded = FALSE;
5889 return hr;
5892 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5894 HRESULT hr = WINED3D_OK;
5895 IWineD3DSurface *tmp;
5897 TRACE("(%p) Swapping z-buffer\n",This);
5899 if (pNewZStencil == This->stencilBufferTarget) {
5900 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5901 } else {
5902 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5903 * depending on the renter target implementation being used.
5904 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5905 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5906 * stencil buffer and incure an extra memory overhead
5907 ******************************************************/
5910 tmp = This->stencilBufferTarget;
5911 This->stencilBufferTarget = pNewZStencil;
5912 /* should we be calling the parent or the wined3d surface? */
5913 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5914 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5915 hr = WINED3D_OK;
5916 /** TODO: glEnable/glDisable on depth/stencil depending on
5917 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5918 **********************************************************/
5919 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5920 set_depth_stencil_fbo(iface, pNewZStencil);
5924 return hr;
5928 #ifdef GL_VERSION_1_3
5929 /* Internal functions not in DirectX */
5930 /** TODO: move this off to the opengl context manager
5931 *(the swapchain doesn't need to know anything about offscreen rendering!)
5932 ****************************************************/
5934 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5938 TRACE("(%p), %p\n", This, swapchain);
5940 if (swapchain->win != swapchain->drawable) {
5941 /* Set everything back the way it ws */
5942 swapchain->render_ctx = swapchain->glCtx;
5943 swapchain->drawable = swapchain->win;
5945 return WINED3D_OK;
5948 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5949 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5951 int i;
5952 unsigned int width;
5953 unsigned int height;
5954 WINED3DFORMAT format;
5955 WINED3DSURFACE_DESC surfaceDesc;
5956 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5957 surfaceDesc.Width = &width;
5958 surfaceDesc.Height = &height;
5959 surfaceDesc.Format = &format;
5960 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5961 *context = NULL;
5962 /* I need a get width/height function (and should do something with the format) */
5963 for (i = 0; i < CONTEXT_CACHE; ++i) {
5964 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5965 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5966 the pSurface can be set to 0 allowing it to be reused from cache **/
5967 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5968 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5969 *context = &This->contextCache[i];
5970 break;
5972 if (This->contextCache[i].Width == 0) {
5973 This->contextCache[i].pSurface = pSurface;
5974 This->contextCache[i].Width = width;
5975 This->contextCache[i].Height = height;
5976 *context = &This->contextCache[i];
5977 break;
5980 if (i == CONTEXT_CACHE) {
5981 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5982 glContext *dropContext = 0;
5983 for (i = 0; i < CONTEXT_CACHE; i++) {
5984 if (This->contextCache[i].usedcount < minUsage) {
5985 dropContext = &This->contextCache[i];
5986 minUsage = This->contextCache[i].usedcount;
5989 /* clean up the context (this doesn't work for ATI at the moment */
5990 #if 0
5991 glXDestroyContext(swapchain->display, dropContext->context);
5992 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5993 #endif
5994 FIXME("Leak\n");
5995 dropContext->Width = 0;
5996 dropContext->pSurface = pSurface;
5997 *context = dropContext;
5998 } else {
5999 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
6000 for (i = 0; i < CONTEXT_CACHE; i++) {
6001 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
6005 if (*context != NULL)
6006 return WINED3D_OK;
6007 else
6008 return E_OUTOFMEMORY;
6010 #endif
6012 /* Reapply the device stateblock */
6013 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
6015 BOOL oldRecording;
6016 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6017 DWORD i;
6019 /* Disable recording */
6020 oldUpdateStateBlock = This->updateStateBlock;
6021 oldRecording= This->isRecordingState;
6022 This->isRecordingState = FALSE;
6023 This->updateStateBlock = This->stateBlock;
6025 /* Reapply the state block */
6026 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
6028 /* Temporaryily mark all render states dirty to force reapplication
6029 * until the context management for is integrated with the state management
6030 * The same for the pixel shader, sampler states and texture stage states are marked
6031 * dirty my StateBlock::Apply already
6033 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
6034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
6036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
6038 /* Restore recording */
6039 This->isRecordingState = oldRecording;
6040 This->updateStateBlock = oldUpdateStateBlock;
6043 /* Set offscreen rendering. When rendering offscreen the surface will be
6044 * rendered upside down to compensate for the fact that D3D texture coordinates
6045 * are flipped compared to GL texture coordinates. The cullmode is affected by
6046 * this, so it must be updated. To update the cullmode stateblock recording has
6047 * to be temporarily disabled. The new state management code will hopefully
6048 * make this unnecessary */
6049 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
6051 BOOL oldRecording;
6052 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6054 /* Nothing to update, return. */
6055 if (This->render_offscreen == isTexture) return;
6057 /* Disable recording */
6058 oldUpdateStateBlock = This->updateStateBlock;
6059 oldRecording= This->isRecordingState;
6060 This->isRecordingState = FALSE;
6061 This->updateStateBlock = This->stateBlock;
6063 This->render_offscreen = isTexture;
6064 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
6065 This->depth_copy_state = WINED3D_DCS_COPY;
6067 This->last_was_rhw = FALSE;
6068 This->proj_valid = FALSE;
6069 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
6071 /* Restore recording */
6072 This->isRecordingState = oldRecording;
6073 This->updateStateBlock = oldUpdateStateBlock;
6076 /* Returns an array of compatible FBconfig(s).
6077 * The array must be freed with XFree. Requires ENTER_GL() */
6079 static GLXFBConfig* device_find_fbconfigs(
6080 IWineD3DDeviceImpl* This,
6081 IWineD3DSwapChainImpl* implicitSwapchainImpl,
6082 IWineD3DSurface* RenderSurface) {
6084 GLXFBConfig* cfgs = NULL;
6085 int nCfgs = 0;
6086 int attribs[256];
6087 int nAttribs = 0;
6089 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
6090 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
6091 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
6093 /**TODO:
6094 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
6095 it StencilSurface != NULL && zBufferTarget == NULL switch it on
6098 #define PUSH1(att) attribs[nAttribs++] = (att);
6099 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
6101 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
6103 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
6104 PUSH2(GLX_X_RENDERABLE, TRUE);
6105 PUSH2(GLX_DOUBLEBUFFER, TRUE);
6106 TRACE("calling makeglcfg\n");
6107 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
6108 PUSH1(None);
6109 TRACE("calling chooseFGConfig\n");
6110 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6111 DefaultScreen(implicitSwapchainImpl->display),
6112 attribs, &nCfgs);
6113 if (cfgs == NULL) {
6114 /* OK we didn't find the exact config, so use any reasonable match */
6115 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
6116 why we failed. */
6117 static BOOL show_message = TRUE;
6118 if (show_message) {
6119 ERR("Failed to find exact match, finding alternative but you may "
6120 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
6121 show_message = FALSE;
6123 nAttribs = 0;
6124 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6125 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
6126 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6127 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6128 TRACE("calling makeglcfg\n");
6129 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6130 PUSH1(None);
6131 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6132 DefaultScreen(implicitSwapchainImpl->display),
6133 attribs, &nCfgs);
6136 if (cfgs == NULL) {
6137 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6138 BackBufferFormat, debug_d3dformat(BackBufferFormat),
6139 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6140 } else {
6141 #ifdef EXTRA_TRACES
6142 int i;
6143 for (i = 0; i < nCfgs; ++i) {
6144 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6145 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6146 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6148 if (NULL != This->renderTarget) {
6149 glFlush();
6150 vcheckGLcall("glFlush");
6151 /** This is only useful if the old render target was a swapchain,
6152 * we need to supercede this with a function that displays
6153 * the current buffer on the screen. This is easy to do in glx1.3 but
6154 * we need to do copy-write pixels in glx 1.2.
6155 ************************************************/
6156 glXSwapBuffers(implicitSwapChainImpl->display,
6157 implicitSwapChainImpl->drawable);
6158 printf("Hit Enter to get next frame ...\n");
6159 getchar();
6161 #endif
6163 #undef PUSH1
6164 #undef PUSH2
6166 return cfgs;
6169 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6170 * the functionality needs splitting up so that we don't do more than we should do.
6171 * this only seems to impact performance a little.
6172 ******************************/
6173 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6174 IWineD3DSurface *RenderSurface) {
6177 * Currently only active for GLX >= 1.3
6178 * for others versions we'll have to use GLXPixmaps
6180 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6181 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6182 * so only check OpenGL version
6183 * ..........................
6184 * I don't believe that it is a problem with NVidia headers,
6185 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6186 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6187 * ATI Note:
6188 * Your application will report GLX version 1.2 on glXQueryVersion.
6189 * However, it is safe to call the GLX 1.3 functions as described below.
6191 #if defined(GL_VERSION_1_3)
6193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 GLXFBConfig* cfgs = NULL;
6195 IWineD3DSwapChain *currentSwapchain;
6196 IWineD3DSwapChainImpl *currentSwapchainImpl;
6197 IWineD3DSwapChain *implicitSwapchain;
6198 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6199 IWineD3DSwapChain *renderSurfaceSwapchain;
6200 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6202 /* Obtain a reference to the device implicit swapchain,
6203 * the swapchain of the current render target,
6204 * and the swapchain of the new render target.
6205 * Fallback to device implicit swapchain if the current render target doesn't have one */
6206 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6207 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6208 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6209 if (currentSwapchain == NULL)
6210 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6212 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6213 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6214 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6216 ENTER_GL();
6219 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6220 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6221 **********************************************************************/
6222 if (renderSurfaceSwapchain != NULL) {
6224 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6225 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6226 TRACE("making swapchain active\n");
6227 if (RenderSurface != This->render_targets[0]) {
6228 BOOL backbuf = FALSE;
6229 int i;
6231 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6232 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6233 backbuf = TRUE;
6234 break;
6238 if (backbuf) {
6239 } else {
6240 /* This could be flagged so that some operations work directly with the front buffer */
6241 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6243 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6244 renderSurfaceSwapchainImpl->win,
6245 renderSurfaceSwapchainImpl->glCtx) == False) {
6247 TRACE("Error in setting current context: context %p drawable %ld !\n",
6248 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6250 checkGLcall("glXMakeContextCurrent");
6252 /* Clean up the old context */
6253 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6255 /* Reapply the stateblock, and set the device not to render to texture */
6256 device_reapply_stateblock(This);
6257 device_render_to_texture(This, FALSE);
6260 /* Offscreen rendering: PBuffers (currently disabled).
6261 * Also note that this path is never reached if FBOs are supported */
6262 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6263 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6265 /** ********************************************************************
6266 * This is a quickly hacked out implementation of offscreen textures.
6267 * It will work in most cases but there may be problems if the client
6268 * modifies the texture directly, or expects the contents of the rendertarget
6269 * to be persistent.
6271 * There are some real speed vs compatibility issues here:
6272 * we should really use a new context for every texture, but that eats ram.
6273 * we should also be restoring the texture to the pbuffer but that eats CPU
6274 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6275 * but if this means reusing the display backbuffer then we need to make sure that
6276 * states are correctly preserved.
6277 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6278 * and gain a good performance increase at the cost of compatibility.
6279 * I would suggest that, when this is the case, a user configurable flag be made
6280 * available, allowing the user to choose the best emulated experience for them.
6281 *********************************************************************/
6283 XVisualInfo *visinfo;
6284 glContext *newContext;
6286 /* Here were using a shared context model */
6287 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6288 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6291 /* If the context doesn't exist then create a new one */
6292 /* TODO: This should really be part of findGlContext */
6293 if (NULL == newContext->context) {
6295 int attribs[256];
6296 int nAttribs = 0;
6298 TRACE("making new buffer\n");
6299 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6300 attribs[nAttribs++] = newContext->Width;
6301 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6302 attribs[nAttribs++] = newContext->Height;
6303 attribs[nAttribs++] = None;
6305 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6307 /** ****************************************
6308 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6309 *they note:
6310 * In future releases, we may provide the calls glXCreateNewContext,
6311 * glXQueryDrawable and glXMakeContextCurrent.
6312 * so until then we have to use glXGetVisualFromFBConfig &co..
6313 ********************************************/
6315 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6316 if (!visinfo) {
6317 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6318 } else {
6319 newContext->context = glXCreateContext(
6320 implicitSwapchainImpl->display, visinfo,
6321 implicitSwapchainImpl->glCtx, GL_TRUE);
6323 XFree(visinfo);
6326 if (NULL == newContext || NULL == newContext->context) {
6327 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6328 } else {
6329 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6330 if (glXMakeCurrent(implicitSwapchainImpl->display,
6331 newContext->drawable, newContext->context) == False) {
6333 TRACE("Error in setting current context: context %p drawable %ld\n",
6334 newContext->context, newContext->drawable);
6336 checkGLcall("glXMakeContextCurrent");
6338 /* Clean up the old context */
6339 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6341 /* Reapply stateblock, and set device to render to a texture */
6342 device_reapply_stateblock(This);
6343 device_render_to_texture(This, TRUE);
6345 /* Set the current context of the swapchain to the new context */
6346 implicitSwapchainImpl->drawable = newContext->drawable;
6347 implicitSwapchainImpl->render_ctx = newContext->context;
6349 } else {
6350 /* Same context, but update render_offscreen and cull mode */
6351 device_render_to_texture(This, TRUE);
6354 if (cfgs != NULL) XFree(cfgs);
6355 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6356 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6357 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6358 LEAVE_GL();
6359 #endif
6360 return WINED3D_OK;
6363 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6364 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6366 /* TODO: the use of Impl is deprecated. */
6367 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6369 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6371 /* some basic validation checks */
6372 if(This->cursorTexture) {
6373 ENTER_GL();
6374 glDeleteTextures(1, &This->cursorTexture);
6375 LEAVE_GL();
6376 This->cursorTexture = 0;
6379 if(pCursorBitmap) {
6380 /* MSDN: Cursor must be A8R8G8B8 */
6381 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6382 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6383 return WINED3DERR_INVALIDCALL;
6386 /* MSDN: Cursor must be smaller than the display mode */
6387 if(pSur->currentDesc.Width > This->ddraw_width ||
6388 pSur->currentDesc.Height > This->ddraw_height) {
6389 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);
6390 return WINED3DERR_INVALIDCALL;
6393 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6394 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6395 * Texture and Blitting code to draw the cursor
6397 pSur->Flags |= SFLAG_FORCELOAD;
6398 IWineD3DSurface_PreLoad(pCursorBitmap);
6399 pSur->Flags &= ~SFLAG_FORCELOAD;
6400 /* Do not store the surface's pointer because the application may release
6401 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6402 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6404 This->cursorTexture = pSur->glDescription.textureName;
6405 This->cursorWidth = pSur->currentDesc.Width;
6406 This->cursorHeight = pSur->currentDesc.Height;
6407 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6410 This->xHotSpot = XHotSpot;
6411 This->yHotSpot = YHotSpot;
6412 return WINED3D_OK;
6415 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6417 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6419 This->xScreenSpace = XScreenSpace;
6420 This->yScreenSpace = YScreenSpace;
6422 return;
6426 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6428 BOOL oldVisible = This->bCursorVisible;
6429 TRACE("(%p) : visible(%d)\n", This, bShow);
6431 if(This->cursorTexture)
6432 This->bCursorVisible = bShow;
6434 return oldVisible;
6437 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6439 TRACE("(%p) : state (%u)\n", This, This->state);
6440 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6441 switch (This->state) {
6442 case WINED3D_OK:
6443 return WINED3D_OK;
6444 case WINED3DERR_DEVICELOST:
6446 ResourceList *resourceList = This->resources;
6447 while (NULL != resourceList) {
6448 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6449 return WINED3DERR_DEVICENOTRESET;
6450 resourceList = resourceList->next;
6452 return WINED3DERR_DEVICELOST;
6454 case WINED3DERR_DRIVERINTERNALERROR:
6455 return WINED3DERR_DRIVERINTERNALERROR;
6458 /* Unknown state */
6459 return WINED3DERR_DRIVERINTERNALERROR;
6463 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6465 /** FIXME: Resource tracking needs to be done,
6466 * The closes we can do to this is set the priorities of all managed textures low
6467 * and then reset them.
6468 ***********************************************************/
6469 FIXME("(%p) : stub\n", This);
6470 return WINED3D_OK;
6473 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6474 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6475 if(surface->Flags & SFLAG_DIBSECTION) {
6476 /* Release the DC */
6477 SelectObject(surface->hDC, surface->dib.holdbitmap);
6478 DeleteDC(surface->hDC);
6479 /* Release the DIB section */
6480 DeleteObject(surface->dib.DIBsection);
6481 surface->dib.bitmap_data = NULL;
6482 surface->resource.allocatedMemory = NULL;
6483 surface->Flags &= ~SFLAG_DIBSECTION;
6485 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6486 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6487 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6488 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6489 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6490 } else {
6491 surface->pow2Width = surface->pow2Height = 1;
6492 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6493 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6495 if(surface->glDescription.textureName) {
6496 ENTER_GL();
6497 glDeleteTextures(1, &surface->glDescription.textureName);
6498 LEAVE_GL();
6499 surface->glDescription.textureName = 0;
6501 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6502 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6503 surface->Flags |= SFLAG_NONPOW2;
6504 } else {
6505 surface->Flags &= ~SFLAG_NONPOW2;
6507 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6508 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6511 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6513 IWineD3DSwapChainImpl *swapchain;
6514 HRESULT hr;
6515 BOOL DisplayModeChanged = FALSE;
6516 WINED3DDISPLAYMODE mode;
6517 TRACE("(%p)\n", This);
6519 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6520 if(FAILED(hr)) {
6521 ERR("Failed to get the first implicit swapchain\n");
6522 return hr;
6525 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6526 * on an existing gl context, so there's no real need for recreation.
6528 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6530 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6532 TRACE("New params:\n");
6533 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6534 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6535 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6536 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6537 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6538 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6539 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6540 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6541 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6542 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6543 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6544 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6545 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6547 /* No special treatment of these parameters. Just store them */
6548 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6549 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6550 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6551 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6553 /* What to do about these? */
6554 if(*pPresentationParameters->BackBufferCount != 0 &&
6555 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6556 ERR("Cannot change the back buffer count yet\n");
6558 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6559 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6560 ERR("Cannot change the back buffer format yet\n");
6562 if(*pPresentationParameters->hDeviceWindow != NULL &&
6563 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6564 ERR("Cannot change the device window yet\n");
6566 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6567 ERR("What do do about a changed auto depth stencil parameter?\n");
6570 if(*pPresentationParameters->Windowed) {
6571 mode.Width = swapchain->orig_width;
6572 mode.Height = swapchain->orig_height;
6573 mode.RefreshRate = 0;
6574 mode.Format = swapchain->presentParms.BackBufferFormat;
6575 } else {
6576 mode.Width = *pPresentationParameters->BackBufferWidth;
6577 mode.Height = *pPresentationParameters->BackBufferHeight;
6578 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6579 mode.Format = swapchain->presentParms.BackBufferFormat;
6582 /* Should Width == 800 && Height == 0 set 800x600? */
6583 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6584 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6585 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6587 WINED3DVIEWPORT vp;
6588 int i;
6590 vp.X = 0;
6591 vp.Y = 0;
6592 vp.Width = *pPresentationParameters->BackBufferWidth;
6593 vp.Height = *pPresentationParameters->BackBufferHeight;
6594 vp.MinZ = 0;
6595 vp.MaxZ = 1;
6597 if(!*pPresentationParameters->Windowed) {
6598 DisplayModeChanged = TRUE;
6600 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6601 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6603 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6604 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6605 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6608 /* Now set the new viewport */
6609 IWineD3DDevice_SetViewport(iface, &vp);
6612 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6613 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6614 DisplayModeChanged) {
6615 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6618 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6619 return WINED3D_OK;
6622 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6624 /** FIXME: always true at the moment **/
6625 if(!bEnableDialogs) {
6626 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6628 return WINED3D_OK;
6632 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6634 TRACE("(%p) : pParameters %p\n", This, pParameters);
6636 *pParameters = This->createParms;
6637 return WINED3D_OK;
6640 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6641 IWineD3DSwapChain *swapchain;
6642 HRESULT hrc = WINED3D_OK;
6644 TRACE("Relaying to swapchain\n");
6646 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6647 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6648 IWineD3DSwapChain_Release(swapchain);
6650 return;
6653 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6654 IWineD3DSwapChain *swapchain;
6655 HRESULT hrc = WINED3D_OK;
6657 TRACE("Relaying to swapchain\n");
6659 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6660 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6661 IWineD3DSwapChain_Release(swapchain);
6663 return;
6667 /** ********************************************************
6668 * Notification functions
6669 ** ********************************************************/
6670 /** This function must be called in the release of a resource when ref == 0,
6671 * the contents of resource must still be correct,
6672 * any handels to other resource held by the caller must be closed
6673 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6674 *****************************************************/
6675 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6677 ResourceList* resourceList;
6679 TRACE("(%p) : resource %p\n", This, resource);
6680 #if 0
6681 EnterCriticalSection(&resourceStoreCriticalSection);
6682 #endif
6683 /* add a new texture to the frot of the linked list */
6684 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6685 resourceList->resource = resource;
6687 /* Get the old head */
6688 resourceList->next = This->resources;
6690 This->resources = resourceList;
6691 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6693 #if 0
6694 LeaveCriticalSection(&resourceStoreCriticalSection);
6695 #endif
6696 return;
6699 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6701 ResourceList* resourceList = NULL;
6702 ResourceList* previousResourceList = NULL;
6704 TRACE("(%p) : resource %p\n", This, resource);
6706 #if 0
6707 EnterCriticalSection(&resourceStoreCriticalSection);
6708 #endif
6709 resourceList = This->resources;
6711 while (resourceList != NULL) {
6712 if(resourceList->resource == resource) break;
6713 previousResourceList = resourceList;
6714 resourceList = resourceList->next;
6717 if (resourceList == NULL) {
6718 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6719 #if 0
6720 LeaveCriticalSection(&resourceStoreCriticalSection);
6721 #endif
6722 return;
6723 } else {
6724 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6726 /* make sure we don't leave a hole in the list */
6727 if (previousResourceList != NULL) {
6728 previousResourceList->next = resourceList->next;
6729 } else {
6730 This->resources = resourceList->next;
6733 #if 0
6734 LeaveCriticalSection(&resourceStoreCriticalSection);
6735 #endif
6736 return;
6740 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6742 int counter;
6744 TRACE("(%p) : resource %p\n", This, resource);
6745 switch(IWineD3DResource_GetType(resource)){
6746 case WINED3DRTYPE_SURFACE:
6747 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6748 break;
6749 case WINED3DRTYPE_TEXTURE:
6750 case WINED3DRTYPE_CUBETEXTURE:
6751 case WINED3DRTYPE_VOLUMETEXTURE:
6752 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6753 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6754 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6755 This->stateBlock->textures[counter] = NULL;
6757 if (This->updateStateBlock != This->stateBlock ){
6758 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6759 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6760 This->updateStateBlock->textures[counter] = NULL;
6764 break;
6765 case WINED3DRTYPE_VOLUME:
6766 /* TODO: nothing really? */
6767 break;
6768 case WINED3DRTYPE_VERTEXBUFFER:
6769 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6771 int streamNumber;
6772 TRACE("Cleaning up stream pointers\n");
6774 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6775 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6776 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6778 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6779 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6780 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6781 This->updateStateBlock->streamSource[streamNumber] = 0;
6782 /* Set changed flag? */
6785 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) */
6786 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6787 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6788 This->stateBlock->streamSource[streamNumber] = 0;
6791 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6792 else { /* This shouldn't happen */
6793 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6795 #endif
6799 break;
6800 case WINED3DRTYPE_INDEXBUFFER:
6801 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6802 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6803 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6804 This->updateStateBlock->pIndexData = NULL;
6807 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6808 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6809 This->stateBlock->pIndexData = NULL;
6813 break;
6814 default:
6815 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6816 break;
6820 /* Remove the resoruce from the resourceStore */
6821 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6823 TRACE("Resource released\n");
6827 /**********************************************************
6828 * IWineD3DDevice VTbl follows
6829 **********************************************************/
6831 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6833 /*** IUnknown methods ***/
6834 IWineD3DDeviceImpl_QueryInterface,
6835 IWineD3DDeviceImpl_AddRef,
6836 IWineD3DDeviceImpl_Release,
6837 /*** IWineD3DDevice methods ***/
6838 IWineD3DDeviceImpl_GetParent,
6839 /*** Creation methods**/
6840 IWineD3DDeviceImpl_CreateVertexBuffer,
6841 IWineD3DDeviceImpl_CreateIndexBuffer,
6842 IWineD3DDeviceImpl_CreateStateBlock,
6843 IWineD3DDeviceImpl_CreateSurface,
6844 IWineD3DDeviceImpl_CreateTexture,
6845 IWineD3DDeviceImpl_CreateVolumeTexture,
6846 IWineD3DDeviceImpl_CreateVolume,
6847 IWineD3DDeviceImpl_CreateCubeTexture,
6848 IWineD3DDeviceImpl_CreateQuery,
6849 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6850 IWineD3DDeviceImpl_CreateVertexDeclaration,
6851 IWineD3DDeviceImpl_CreateVertexShader,
6852 IWineD3DDeviceImpl_CreatePixelShader,
6853 IWineD3DDeviceImpl_CreatePalette,
6854 /*** Odd functions **/
6855 IWineD3DDeviceImpl_Init3D,
6856 IWineD3DDeviceImpl_Uninit3D,
6857 IWineD3DDeviceImpl_SetFullscreen,
6858 IWineD3DDeviceImpl_EnumDisplayModes,
6859 IWineD3DDeviceImpl_EvictManagedResources,
6860 IWineD3DDeviceImpl_GetAvailableTextureMem,
6861 IWineD3DDeviceImpl_GetBackBuffer,
6862 IWineD3DDeviceImpl_GetCreationParameters,
6863 IWineD3DDeviceImpl_GetDeviceCaps,
6864 IWineD3DDeviceImpl_GetDirect3D,
6865 IWineD3DDeviceImpl_GetDisplayMode,
6866 IWineD3DDeviceImpl_SetDisplayMode,
6867 IWineD3DDeviceImpl_GetHWND,
6868 IWineD3DDeviceImpl_SetHWND,
6869 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6870 IWineD3DDeviceImpl_GetRasterStatus,
6871 IWineD3DDeviceImpl_GetSwapChain,
6872 IWineD3DDeviceImpl_Reset,
6873 IWineD3DDeviceImpl_SetDialogBoxMode,
6874 IWineD3DDeviceImpl_SetCursorProperties,
6875 IWineD3DDeviceImpl_SetCursorPosition,
6876 IWineD3DDeviceImpl_ShowCursor,
6877 IWineD3DDeviceImpl_TestCooperativeLevel,
6878 /*** Getters and setters **/
6879 IWineD3DDeviceImpl_SetClipPlane,
6880 IWineD3DDeviceImpl_GetClipPlane,
6881 IWineD3DDeviceImpl_SetClipStatus,
6882 IWineD3DDeviceImpl_GetClipStatus,
6883 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6884 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6885 IWineD3DDeviceImpl_SetDepthStencilSurface,
6886 IWineD3DDeviceImpl_GetDepthStencilSurface,
6887 IWineD3DDeviceImpl_SetFVF,
6888 IWineD3DDeviceImpl_GetFVF,
6889 IWineD3DDeviceImpl_SetGammaRamp,
6890 IWineD3DDeviceImpl_GetGammaRamp,
6891 IWineD3DDeviceImpl_SetIndices,
6892 IWineD3DDeviceImpl_GetIndices,
6893 IWineD3DDeviceImpl_SetLight,
6894 IWineD3DDeviceImpl_GetLight,
6895 IWineD3DDeviceImpl_SetLightEnable,
6896 IWineD3DDeviceImpl_GetLightEnable,
6897 IWineD3DDeviceImpl_SetMaterial,
6898 IWineD3DDeviceImpl_GetMaterial,
6899 IWineD3DDeviceImpl_SetNPatchMode,
6900 IWineD3DDeviceImpl_GetNPatchMode,
6901 IWineD3DDeviceImpl_SetPaletteEntries,
6902 IWineD3DDeviceImpl_GetPaletteEntries,
6903 IWineD3DDeviceImpl_SetPixelShader,
6904 IWineD3DDeviceImpl_GetPixelShader,
6905 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6906 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6907 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6908 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6909 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6910 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6911 IWineD3DDeviceImpl_SetRenderState,
6912 IWineD3DDeviceImpl_GetRenderState,
6913 IWineD3DDeviceImpl_SetRenderTarget,
6914 IWineD3DDeviceImpl_GetRenderTarget,
6915 IWineD3DDeviceImpl_SetFrontBackBuffers,
6916 IWineD3DDeviceImpl_SetSamplerState,
6917 IWineD3DDeviceImpl_GetSamplerState,
6918 IWineD3DDeviceImpl_SetScissorRect,
6919 IWineD3DDeviceImpl_GetScissorRect,
6920 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6921 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6922 IWineD3DDeviceImpl_SetStreamSource,
6923 IWineD3DDeviceImpl_GetStreamSource,
6924 IWineD3DDeviceImpl_SetStreamSourceFreq,
6925 IWineD3DDeviceImpl_GetStreamSourceFreq,
6926 IWineD3DDeviceImpl_SetTexture,
6927 IWineD3DDeviceImpl_GetTexture,
6928 IWineD3DDeviceImpl_SetTextureStageState,
6929 IWineD3DDeviceImpl_GetTextureStageState,
6930 IWineD3DDeviceImpl_SetTransform,
6931 IWineD3DDeviceImpl_GetTransform,
6932 IWineD3DDeviceImpl_SetVertexDeclaration,
6933 IWineD3DDeviceImpl_GetVertexDeclaration,
6934 IWineD3DDeviceImpl_SetVertexShader,
6935 IWineD3DDeviceImpl_GetVertexShader,
6936 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6937 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6938 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6939 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6940 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6941 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6942 IWineD3DDeviceImpl_SetViewport,
6943 IWineD3DDeviceImpl_GetViewport,
6944 IWineD3DDeviceImpl_MultiplyTransform,
6945 IWineD3DDeviceImpl_ValidateDevice,
6946 IWineD3DDeviceImpl_ProcessVertices,
6947 /*** State block ***/
6948 IWineD3DDeviceImpl_BeginStateBlock,
6949 IWineD3DDeviceImpl_EndStateBlock,
6950 /*** Scene management ***/
6951 IWineD3DDeviceImpl_BeginScene,
6952 IWineD3DDeviceImpl_EndScene,
6953 IWineD3DDeviceImpl_Present,
6954 IWineD3DDeviceImpl_Clear,
6955 /*** Drawing ***/
6956 IWineD3DDeviceImpl_DrawPrimitive,
6957 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6958 IWineD3DDeviceImpl_DrawPrimitiveUP,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6960 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6961 IWineD3DDeviceImpl_DrawRectPatch,
6962 IWineD3DDeviceImpl_DrawTriPatch,
6963 IWineD3DDeviceImpl_DeletePatch,
6964 IWineD3DDeviceImpl_ColorFill,
6965 IWineD3DDeviceImpl_UpdateTexture,
6966 IWineD3DDeviceImpl_UpdateSurface,
6967 IWineD3DDeviceImpl_StretchRect,
6968 IWineD3DDeviceImpl_GetRenderTargetData,
6969 IWineD3DDeviceImpl_GetFrontBufferData,
6970 /*** Internal use IWineD3DDevice methods ***/
6971 IWineD3DDeviceImpl_SetupTextureStates,
6972 /*** object tracking ***/
6973 IWineD3DDeviceImpl_ResourceReleased
6977 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6978 WINED3DRS_ALPHABLENDENABLE ,
6979 WINED3DRS_ALPHAFUNC ,
6980 WINED3DRS_ALPHAREF ,
6981 WINED3DRS_ALPHATESTENABLE ,
6982 WINED3DRS_BLENDOP ,
6983 WINED3DRS_COLORWRITEENABLE ,
6984 WINED3DRS_DESTBLEND ,
6985 WINED3DRS_DITHERENABLE ,
6986 WINED3DRS_FILLMODE ,
6987 WINED3DRS_FOGDENSITY ,
6988 WINED3DRS_FOGEND ,
6989 WINED3DRS_FOGSTART ,
6990 WINED3DRS_LASTPIXEL ,
6991 WINED3DRS_SHADEMODE ,
6992 WINED3DRS_SRCBLEND ,
6993 WINED3DRS_STENCILENABLE ,
6994 WINED3DRS_STENCILFAIL ,
6995 WINED3DRS_STENCILFUNC ,
6996 WINED3DRS_STENCILMASK ,
6997 WINED3DRS_STENCILPASS ,
6998 WINED3DRS_STENCILREF ,
6999 WINED3DRS_STENCILWRITEMASK ,
7000 WINED3DRS_STENCILZFAIL ,
7001 WINED3DRS_TEXTUREFACTOR ,
7002 WINED3DRS_WRAP0 ,
7003 WINED3DRS_WRAP1 ,
7004 WINED3DRS_WRAP2 ,
7005 WINED3DRS_WRAP3 ,
7006 WINED3DRS_WRAP4 ,
7007 WINED3DRS_WRAP5 ,
7008 WINED3DRS_WRAP6 ,
7009 WINED3DRS_WRAP7 ,
7010 WINED3DRS_ZENABLE ,
7011 WINED3DRS_ZFUNC ,
7012 WINED3DRS_ZWRITEENABLE
7015 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7016 WINED3DTSS_ADDRESSW ,
7017 WINED3DTSS_ALPHAARG0 ,
7018 WINED3DTSS_ALPHAARG1 ,
7019 WINED3DTSS_ALPHAARG2 ,
7020 WINED3DTSS_ALPHAOP ,
7021 WINED3DTSS_BUMPENVLOFFSET ,
7022 WINED3DTSS_BUMPENVLSCALE ,
7023 WINED3DTSS_BUMPENVMAT00 ,
7024 WINED3DTSS_BUMPENVMAT01 ,
7025 WINED3DTSS_BUMPENVMAT10 ,
7026 WINED3DTSS_BUMPENVMAT11 ,
7027 WINED3DTSS_COLORARG0 ,
7028 WINED3DTSS_COLORARG1 ,
7029 WINED3DTSS_COLORARG2 ,
7030 WINED3DTSS_COLOROP ,
7031 WINED3DTSS_RESULTARG ,
7032 WINED3DTSS_TEXCOORDINDEX ,
7033 WINED3DTSS_TEXTURETRANSFORMFLAGS
7036 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7037 WINED3DSAMP_ADDRESSU ,
7038 WINED3DSAMP_ADDRESSV ,
7039 WINED3DSAMP_ADDRESSW ,
7040 WINED3DSAMP_BORDERCOLOR ,
7041 WINED3DSAMP_MAGFILTER ,
7042 WINED3DSAMP_MINFILTER ,
7043 WINED3DSAMP_MIPFILTER ,
7044 WINED3DSAMP_MIPMAPLODBIAS ,
7045 WINED3DSAMP_MAXMIPLEVEL ,
7046 WINED3DSAMP_MAXANISOTROPY ,
7047 WINED3DSAMP_SRGBTEXTURE ,
7048 WINED3DSAMP_ELEMENTINDEX
7051 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7052 WINED3DRS_AMBIENT ,
7053 WINED3DRS_AMBIENTMATERIALSOURCE ,
7054 WINED3DRS_CLIPPING ,
7055 WINED3DRS_CLIPPLANEENABLE ,
7056 WINED3DRS_COLORVERTEX ,
7057 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7058 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7059 WINED3DRS_FOGDENSITY ,
7060 WINED3DRS_FOGEND ,
7061 WINED3DRS_FOGSTART ,
7062 WINED3DRS_FOGTABLEMODE ,
7063 WINED3DRS_FOGVERTEXMODE ,
7064 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7065 WINED3DRS_LIGHTING ,
7066 WINED3DRS_LOCALVIEWER ,
7067 WINED3DRS_MULTISAMPLEANTIALIAS ,
7068 WINED3DRS_MULTISAMPLEMASK ,
7069 WINED3DRS_NORMALIZENORMALS ,
7070 WINED3DRS_PATCHEDGESTYLE ,
7071 WINED3DRS_POINTSCALE_A ,
7072 WINED3DRS_POINTSCALE_B ,
7073 WINED3DRS_POINTSCALE_C ,
7074 WINED3DRS_POINTSCALEENABLE ,
7075 WINED3DRS_POINTSIZE ,
7076 WINED3DRS_POINTSIZE_MAX ,
7077 WINED3DRS_POINTSIZE_MIN ,
7078 WINED3DRS_POINTSPRITEENABLE ,
7079 WINED3DRS_RANGEFOGENABLE ,
7080 WINED3DRS_SPECULARMATERIALSOURCE ,
7081 WINED3DRS_TWEENFACTOR ,
7082 WINED3DRS_VERTEXBLEND
7085 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7086 WINED3DTSS_TEXCOORDINDEX ,
7087 WINED3DTSS_TEXTURETRANSFORMFLAGS
7090 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7091 WINED3DSAMP_DMAPOFFSET
7094 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7095 DWORD rep = StateTable[state].representative;
7096 DWORD idx;
7097 BYTE shift;
7099 if(!rep || isStateDirty(This, rep)) return;
7101 This->dirtyArray[This->numDirtyEntries++] = rep;
7102 idx = rep >> 5;
7103 shift = rep & 0x1f;
7104 This->isStateDirty[idx] |= (1 << shift);