Correct GetDeviceCaps so that it uses wined3dcaps as required by the
[wine/multimedia.git] / dlls / wined3d / directx.c
blobdeb5e1925c90880e3e2850a0399915b8f3451661
1 /*
2 * IWineD3D implementation
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2003-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* Compile time diagnostics: */
25 /* Uncomment this to force only a single display mode to be exposed: */
26 /*#define DEBUG_SINGLE_MODE*/
29 #include "config.h"
30 #include "wined3d_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
33 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
34 #define GLINFO_LOCATION This->gl_info
36 /**********************************************************
37 * Utility functions follow
38 **********************************************************/
40 /* x11drv GDI escapes */
41 #define X11DRV_ESCAPE 6789
42 enum x11drv_escape_codes
44 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
45 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
46 X11DRV_GET_FONT, /* get current X font for a DC */
49 /* retrieve the X display to use on a given DC */
50 inline static Display *get_display( HDC hdc )
52 Display *display;
53 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
55 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
56 sizeof(display), (LPSTR)&display )) display = NULL;
57 return display;
60 /**
61 * Note: GL seems to trap if GetDeviceCaps is called before any HWND's created
62 * ie there is no GL Context - Get a default rendering context to enable the
63 * function query some info from GL
64 */
65 static WineD3D_Context* WineD3D_CreateFakeGLContext(void) {
66 static WineD3D_Context ctx = { NULL, NULL, NULL, 0, 0 };
67 WineD3D_Context* ret = NULL;
69 if (glXGetCurrentContext() == NULL) {
70 BOOL gotContext = FALSE;
71 BOOL created = FALSE;
72 XVisualInfo template;
73 HDC device_context;
74 Visual* visual;
75 BOOL failed = FALSE;
76 int num;
77 XWindowAttributes win_attr;
79 TRACE_(d3d_caps)("Creating Fake GL Context\n");
81 ctx.drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
83 /* Get the display */
84 device_context = GetDC(0);
85 ctx.display = get_display(device_context);
86 ReleaseDC(0, device_context);
88 /* Get the X visual */
89 ENTER_GL();
90 if (XGetWindowAttributes(ctx.display, ctx.drawable, &win_attr)) {
91 visual = win_attr.visual;
92 } else {
93 visual = DefaultVisual(ctx.display, DefaultScreen(ctx.display));
95 template.visualid = XVisualIDFromVisual(visual);
96 ctx.visInfo = XGetVisualInfo(ctx.display, VisualIDMask, &template, &num);
97 if (ctx.visInfo == NULL) {
98 LEAVE_GL();
99 WARN_(d3d_caps)("Error creating visual info for capabilities initialization\n");
100 failed = TRUE;
103 /* Create a GL context */
104 if (!failed) {
105 ctx.glCtx = glXCreateContext(ctx.display, ctx.visInfo, NULL, GL_TRUE);
107 if (ctx.glCtx == NULL) {
108 LEAVE_GL();
109 WARN_(d3d_caps)("Error creating default context for capabilities initialization\n");
110 failed = TRUE;
114 /* Make it the current GL context */
115 if (!failed && glXMakeCurrent(ctx.display, ctx.drawable, ctx.glCtx) == False) {
116 glXDestroyContext(ctx.display, ctx.glCtx);
117 LEAVE_GL();
118 WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n");
119 failed = TRUE;
122 /* It worked! Wow... */
123 if (!failed) {
124 gotContext = TRUE;
125 created = TRUE;
126 ret = &ctx;
127 } else {
128 ret = NULL;
131 } else {
132 if (ctx.ref > 0) ret = &ctx;
135 if (NULL != ret) InterlockedIncrement(&ret->ref);
136 return ret;
139 static void WineD3D_ReleaseFakeGLContext(WineD3D_Context* ctx) {
140 /* If we created a dummy context, throw it away */
141 if (NULL != ctx) {
142 if (0 == InterlockedDecrement(&ctx->ref)) {
143 glXMakeCurrent(ctx->display, None, NULL);
144 glXDestroyContext(ctx->display, ctx->glCtx);
145 ctx->display = NULL;
146 ctx->glCtx = NULL;
147 LEAVE_GL();
152 /**********************************************************
153 * IUnknown parts follows
154 **********************************************************/
156 HRESULT WINAPI IWineD3DImpl_QueryInterface(IWineD3D *iface,REFIID riid,LPVOID *ppobj)
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
159 /* FIXME: This needs to extend an IWineD3DBaseObject */
161 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
162 if (IsEqualGUID(riid, &IID_IUnknown)
163 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
164 IUnknown_AddRef(iface);
165 *ppobj = This;
166 return D3D_OK;
169 return E_NOINTERFACE;
172 ULONG WINAPI IWineD3DImpl_AddRef(IWineD3D *iface) {
173 IWineD3DImpl *This = (IWineD3DImpl *)iface;
174 ULONG refCount = InterlockedIncrement(&This->ref);
176 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
177 return refCount;
180 ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) {
181 IWineD3DImpl *This = (IWineD3DImpl *)iface;
182 ULONG ref;
183 TRACE("(%p) : Releasing from %ld\n", This, This->ref);
184 ref = InterlockedDecrement(&This->ref);
185 if (ref == 0) {
186 HeapFree(GetProcessHeap(), 0, This);
189 return ref;
192 /**********************************************************
193 * IWineD3D parts follows
194 **********************************************************/
196 static BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info, Display* display) {
197 const char *GL_Extensions = NULL;
198 const char *GLX_Extensions = NULL;
199 const char *gl_string = NULL;
200 const char *gl_string_cursor = NULL;
201 GLint gl_max;
202 Bool test = 0;
203 int major, minor;
205 TRACE_(d3d_caps)("(%p, %p)\n", gl_info, display);
207 /* Fill in the GL info retrievable depending on the display */
208 if (NULL != display) {
209 test = glXQueryVersion(display, &major, &minor);
210 gl_info->glx_version = ((major & 0x0000FFFF) << 16) | (minor & 0x0000FFFF);
211 gl_string = glXGetClientString(display, GLX_VENDOR);
212 } else {
213 gl_string = glGetString(GL_VENDOR);
216 /* Fill in the GL vendor */
217 if (strstr(gl_string, "NVIDIA")) {
218 gl_info->gl_vendor = VENDOR_NVIDIA;
219 } else if (strstr(gl_string, "ATI")) {
220 gl_info->gl_vendor = VENDOR_ATI;
221 } else {
222 gl_info->gl_vendor = VENDOR_WINE;
225 TRACE_(d3d_caps)("found GL_VENDOR (%s)->(0x%04x)\n", debugstr_a(gl_string), gl_info->gl_vendor);
227 /* Parse the GL_VERSION field into major and minor information */
228 gl_string = glGetString(GL_VERSION);
229 switch (gl_info->gl_vendor) {
230 case VENDOR_NVIDIA:
231 gl_string_cursor = strstr(gl_string, "NVIDIA");
232 gl_string_cursor = strstr(gl_string_cursor, " ");
233 while (*gl_string_cursor && ' ' == *gl_string_cursor) ++gl_string_cursor;
234 if (*gl_string_cursor) {
235 char tmp[16];
236 int cursor = 0;
238 while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') {
239 tmp[cursor++] = *gl_string_cursor;
240 ++gl_string_cursor;
242 tmp[cursor] = 0;
243 major = atoi(tmp);
245 if (*gl_string_cursor != '.') WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string));
246 ++gl_string_cursor;
248 while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') {
249 tmp[cursor++] = *gl_string_cursor;
250 ++gl_string_cursor;
252 tmp[cursor] = 0;
253 minor = atoi(tmp);
255 break;
257 case VENDOR_ATI:
258 major = minor = 0;
259 gl_string_cursor = strchr(gl_string, '-');
260 if (gl_string_cursor) {
261 int error = 0;
262 gl_string_cursor++;
264 /* Check if version number is of the form x.y.z */
265 if (*gl_string_cursor > '9' && *gl_string_cursor < '0')
266 error = 1;
267 if (!error && *(gl_string_cursor+2) > '9' && *(gl_string_cursor+2) < '0')
268 error = 1;
269 if (!error && *(gl_string_cursor+4) > '9' && *(gl_string_cursor+4) < '0')
270 error = 1;
271 if (!error && *(gl_string_cursor+1) != '.' && *(gl_string_cursor+3) != '.')
272 error = 1;
274 /* Mark version number as malformed */
275 if (error)
276 gl_string_cursor = 0;
279 if (!gl_string_cursor)
280 WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string));
281 else {
282 major = *gl_string_cursor - '0';
283 minor = (*(gl_string_cursor+2) - '0') * 256 + (*(gl_string_cursor+4) - '0');
285 break;
287 default:
288 major = 0;
289 minor = 9;
291 gl_info->gl_driver_version = MAKEDWORD_VERSION(major, minor);
292 TRACE_(d3d_caps)("found GL_VERSION (%s)->(0x%08lx)\n", debugstr_a(gl_string), gl_info->gl_driver_version);
294 /* Fill in the renderer information */
295 gl_string = glGetString(GL_RENDERER);
296 strcpy(gl_info->gl_renderer, gl_string);
298 switch (gl_info->gl_vendor) {
299 case VENDOR_NVIDIA:
300 if (strstr(gl_info->gl_renderer, "GeForce4 Ti")) {
301 gl_info->gl_card = CARD_NVIDIA_GEFORCE4_TI4600;
302 } else if (strstr(gl_info->gl_renderer, "GeForceFX")) {
303 gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5900ULTRA;
304 } else {
305 gl_info->gl_card = CARD_NVIDIA_GEFORCE4_TI4600;
307 break;
309 case VENDOR_ATI:
310 if (strstr(gl_info->gl_renderer, "RADEON 9800 PRO")) {
311 gl_info->gl_card = CARD_ATI_RADEON_9800PRO;
312 } else if (strstr(gl_info->gl_renderer, "RADEON 9700 PRO")) {
313 gl_info->gl_card = CARD_ATI_RADEON_9700PRO;
314 } else {
315 gl_info->gl_card = CARD_ATI_RADEON_8500;
317 break;
319 default:
320 gl_info->gl_card = CARD_WINE;
321 break;
324 TRACE_(d3d_caps)("found GL_RENDERER (%s)->(0x%04x)\n", debugstr_a(gl_info->gl_renderer), gl_info->gl_card);
327 * Initialize openGL extension related variables
328 * with Default values
330 memset(&gl_info->supported, 0, sizeof(gl_info->supported));
331 gl_info->max_textures = 1;
332 gl_info->ps_arb_version = PS_VERSION_NOT_SUPPORTED;
333 gl_info->vs_arb_version = VS_VERSION_NOT_SUPPORTED;
334 gl_info->vs_nv_version = VS_VERSION_NOT_SUPPORTED;
335 gl_info->vs_ati_version = VS_VERSION_NOT_SUPPORTED;
337 /* Now work out what GL support this card really has */
338 #define USE_GL_FUNC(type, pfn) gl_info->pfn = NULL;
339 GL_EXT_FUNCS_GEN;
340 #undef USE_GL_FUNC
342 /* Retrieve opengl defaults */
343 glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_max);
344 gl_info->max_clipplanes = min(D3DMAXUSERCLIPPLANES, gl_max);
345 TRACE_(d3d_caps)("ClipPlanes support - num Planes=%d\n", gl_max);
347 glGetIntegerv(GL_MAX_LIGHTS, &gl_max);
348 gl_info->max_lights = gl_max;
349 TRACE_(d3d_caps)("Lights support - max lights=%d\n", gl_max);
351 /* Parse the gl supported features, in theory enabling parts of our code appropriately */
352 GL_Extensions = glGetString(GL_EXTENSIONS);
353 TRACE_(d3d_caps)("GL_Extensions reported:\n");
355 if (NULL == GL_Extensions) {
356 ERR(" GL_Extensions returns NULL\n");
357 } else {
358 while (*GL_Extensions != 0x00) {
359 const char *Start = GL_Extensions;
360 char ThisExtn[256];
362 memset(ThisExtn, 0x00, sizeof(ThisExtn));
363 while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
364 GL_Extensions++;
366 memcpy(ThisExtn, Start, (GL_Extensions - Start));
367 TRACE_(d3d_caps)("- %s\n", ThisExtn);
370 * ARB
372 if (strcmp(ThisExtn, "GL_ARB_fragment_program") == 0) {
373 gl_info->ps_arb_version = PS_VERSION_11;
374 TRACE_(d3d_caps)(" FOUND: ARB Pixel Shader support - version=%02x\n", gl_info->ps_arb_version);
375 gl_info->supported[ARB_FRAGMENT_PROGRAM] = TRUE;
376 } else if (strcmp(ThisExtn, "GL_ARB_multisample") == 0) {
377 TRACE_(d3d_caps)(" FOUND: ARB Multisample support\n");
378 gl_info->supported[ARB_MULTISAMPLE] = TRUE;
379 } else if (strcmp(ThisExtn, "GL_ARB_multitexture") == 0) {
380 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_max);
381 TRACE_(d3d_caps)(" FOUND: ARB Multitexture support - GL_MAX_TEXTURE_UNITS_ARB=%u\n", gl_max);
382 gl_info->supported[ARB_MULTITEXTURE] = TRUE;
383 gl_info->max_textures = min(8, gl_max);
384 } else if (strcmp(ThisExtn, "GL_ARB_texture_cube_map") == 0) {
385 TRACE_(d3d_caps)(" FOUND: ARB Texture Cube Map support\n");
386 gl_info->supported[ARB_TEXTURE_CUBE_MAP] = TRUE;
387 TRACE_(d3d_caps)(" IMPLIED: NVIDIA (NV) Texture Gen Reflection support\n");
388 gl_info->supported[NV_TEXGEN_REFLECTION] = TRUE;
389 } else if (strcmp(ThisExtn, "GL_ARB_texture_compression") == 0) {
390 TRACE_(d3d_caps)(" FOUND: ARB Texture Compression support\n");
391 gl_info->supported[ARB_TEXTURE_COMPRESSION] = TRUE;
392 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_add") == 0) {
393 TRACE_(d3d_caps)(" FOUND: ARB Texture Env Add support\n");
394 gl_info->supported[ARB_TEXTURE_ENV_ADD] = TRUE;
395 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_combine") == 0) {
396 TRACE_(d3d_caps)(" FOUND: ARB Texture Env combine support\n");
397 gl_info->supported[ARB_TEXTURE_ENV_COMBINE] = TRUE;
398 } else if (strcmp(ThisExtn, "GL_ARB_texture_env_dot3") == 0) {
399 TRACE_(d3d_caps)(" FOUND: ARB Dot3 support\n");
400 gl_info->supported[ARB_TEXTURE_ENV_DOT3] = TRUE;
401 } else if (strcmp(ThisExtn, "GL_ARB_texture_border_clamp") == 0) {
402 TRACE_(d3d_caps)(" FOUND: ARB Texture border clamp support\n");
403 gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] = TRUE;
404 } else if (strcmp(ThisExtn, "GL_ARB_texture_mirrored_repeat") == 0) {
405 TRACE_(d3d_caps)(" FOUND: ARB Texture mirrored repeat support\n");
406 gl_info->supported[ARB_TEXTURE_MIRRORED_REPEAT] = TRUE;
407 } else if (strstr(ThisExtn, "GL_ARB_vertex_program")) {
408 gl_info->vs_arb_version = VS_VERSION_11;
409 TRACE_(d3d_caps)(" FOUND: ARB Vertex Shader support - version=%02x\n", gl_info->vs_arb_version);
410 gl_info->supported[ARB_VERTEX_PROGRAM] = TRUE;
411 } else if (strcmp(ThisExtn, "GL_ARB_vertex_blend") == 0) {
412 TRACE_(d3d_caps)(" FOUND: ARB Vertex Blend support\n");
413 gl_info->supported[ARB_VERTEX_BLEND] = TRUE;
414 } else if (strcmp(ThisExtn, "GL_ARB_vertex_buffer_object") == 0) {
415 TRACE_(d3d_caps)(" FOUND: ARB Vertex Buffer support\n");
416 gl_info->supported[ARB_VERTEX_BUFFER_OBJECT] = TRUE;
419 * EXT
421 } else if (strcmp(ThisExtn, "GL_EXT_fog_coord") == 0) {
422 TRACE_(d3d_caps)(" FOUND: EXT Fog coord support\n");
423 gl_info->supported[EXT_FOG_COORD] = TRUE;
424 } else if (strcmp(ThisExtn, "GL_EXT_paletted_texture") == 0) { /* handle paletted texture extensions */
425 TRACE_(d3d_caps)(" FOUND: EXT Paletted texture support\n");
426 gl_info->supported[EXT_PALETTED_TEXTURE] = TRUE;
427 } else if (strcmp(ThisExtn, "GL_EXT_point_parameters") == 0) {
428 TRACE_(d3d_caps)(" FOUND: EXT Point parameters support\n");
429 gl_info->supported[EXT_POINT_PARAMETERS] = TRUE;
430 } else if (strcmp(ThisExtn, "GL_EXT_secondary_color") == 0) {
431 TRACE_(d3d_caps)(" FOUND: EXT Secondary coord support\n");
432 gl_info->supported[EXT_SECONDARY_COLOR] = TRUE;
433 } else if (strcmp(ThisExtn, "GL_EXT_stencil_wrap") == 0) {
434 TRACE_(d3d_caps)(" FOUND: EXT Stencil wrap support\n");
435 gl_info->supported[EXT_STENCIL_WRAP] = TRUE;
436 } else if (strcmp(ThisExtn, "GL_EXT_texture_compression_s3tc") == 0) {
437 TRACE_(d3d_caps)(" FOUND: EXT Texture S3TC compression support\n");
438 gl_info->supported[EXT_TEXTURE_COMPRESSION_S3TC] = TRUE;
439 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_add") == 0) {
440 TRACE_(d3d_caps)(" FOUND: EXT Texture Env Add support\n");
441 gl_info->supported[EXT_TEXTURE_ENV_ADD] = TRUE;
442 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_combine") == 0) {
443 TRACE_(d3d_caps)(" FOUND: EXT Texture Env combine support\n");
444 gl_info->supported[EXT_TEXTURE_ENV_COMBINE] = TRUE;
445 } else if (strcmp(ThisExtn, "GL_EXT_texture_env_dot3") == 0) {
446 TRACE_(d3d_caps)(" FOUND: EXT Dot3 support\n");
447 gl_info->supported[EXT_TEXTURE_ENV_DOT3] = TRUE;
448 } else if (strcmp(ThisExtn, "GL_EXT_texture_filter_anisotropic") == 0) {
449 TRACE_(d3d_caps)(" FOUND: EXT Texture Anisotropic filter support\n");
450 gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] = TRUE;
451 } else if (strcmp(ThisExtn, "GL_EXT_texture_lod") == 0) {
452 TRACE_(d3d_caps)(" FOUND: EXT Texture LOD support\n");
453 gl_info->supported[EXT_TEXTURE_LOD] = TRUE;
454 } else if (strcmp(ThisExtn, "GL_EXT_texture_lod_bias") == 0) {
455 TRACE_(d3d_caps)(" FOUND: EXT Texture LOD bias support\n");
456 gl_info->supported[EXT_TEXTURE_LOD_BIAS] = TRUE;
457 } else if (strcmp(ThisExtn, "GL_EXT_vertex_weighting") == 0) {
458 TRACE_(d3d_caps)(" FOUND: EXT Vertex weighting support\n");
459 gl_info->supported[EXT_VERTEX_WEIGHTING] = TRUE;
462 * NVIDIA
464 } else if (strstr(ThisExtn, "GL_NV_fog_distance")) {
465 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Fog Distance support\n");
466 gl_info->supported[NV_FOG_DISTANCE] = TRUE;
467 } else if (strstr(ThisExtn, "GL_NV_fragment_program")) {
468 gl_info->ps_nv_version = PS_VERSION_11;
469 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Pixel Shader support - version=%02x\n", gl_info->ps_nv_version);
470 } else if (strcmp(ThisExtn, "GL_NV_register_combiners") == 0) {
471 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Register combiners (1) support\n");
472 gl_info->supported[NV_REGISTER_COMBINERS] = TRUE;
473 } else if (strcmp(ThisExtn, "GL_NV_register_combiners2") == 0) {
474 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Register combiners (2) support\n");
475 gl_info->supported[NV_REGISTER_COMBINERS2] = TRUE;
476 } else if (strcmp(ThisExtn, "GL_NV_texgen_reflection") == 0) {
477 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Gen Reflection support\n");
478 gl_info->supported[NV_TEXGEN_REFLECTION] = TRUE;
479 } else if (strcmp(ThisExtn, "GL_NV_texture_env_combine4") == 0) {
480 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Env combine (4) support\n");
481 gl_info->supported[NV_TEXTURE_ENV_COMBINE4] = TRUE;
482 } else if (strcmp(ThisExtn, "GL_NV_texture_shader") == 0) {
483 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (1) support\n");
484 gl_info->supported[NV_TEXTURE_SHADER] = TRUE;
485 } else if (strcmp(ThisExtn, "GL_NV_texture_shader2") == 0) {
486 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (2) support\n");
487 gl_info->supported[NV_TEXTURE_SHADER2] = TRUE;
488 } else if (strcmp(ThisExtn, "GL_NV_texture_shader3") == 0) {
489 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Texture Shader (3) support\n");
490 gl_info->supported[NV_TEXTURE_SHADER3] = TRUE;
491 } else if (strstr(ThisExtn, "GL_NV_vertex_program")) {
492 gl_info->vs_nv_version = max(gl_info->vs_nv_version, (0 == strcmp(ThisExtn, "GL_NV_vertex_program1_1")) ? VS_VERSION_11 : VS_VERSION_10);
493 gl_info->vs_nv_version = max(gl_info->vs_nv_version, (0 == strcmp(ThisExtn, "GL_NV_vertex_program2")) ? VS_VERSION_20 : VS_VERSION_10);
494 TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Vertex Shader support - version=%02x\n", gl_info->vs_nv_version);
495 gl_info->supported[NV_VERTEX_PROGRAM] = TRUE;
498 * ATI
500 /** TODO */
501 } else if (strcmp(ThisExtn, "GL_ATI_texture_env_combine3") == 0) {
502 TRACE_(d3d_caps)(" FOUND: ATI Texture Env combine (3) support\n");
503 gl_info->supported[ATI_TEXTURE_ENV_COMBINE3] = TRUE;
504 } else if (strcmp(ThisExtn, "GL_ATI_texture_mirror_once") == 0) {
505 TRACE_(d3d_caps)(" FOUND: ATI Texture Mirror Once support\n");
506 gl_info->supported[ATI_TEXTURE_MIRROR_ONCE] = TRUE;
507 } else if (strcmp(ThisExtn, "GL_EXT_vertex_shader") == 0) {
508 gl_info->vs_ati_version = VS_VERSION_11;
509 TRACE_(d3d_caps)(" FOUND: ATI (EXT) Vertex Shader support - version=%02x\n", gl_info->vs_ati_version);
510 gl_info->supported[EXT_VERTEX_SHADER] = TRUE;
514 if (*GL_Extensions == ' ') GL_Extensions++;
518 #define USE_GL_FUNC(type, pfn) gl_info->pfn = (type) glXGetProcAddressARB(#pfn);
519 GL_EXT_FUNCS_GEN;
520 #undef USE_GL_FUNC
522 if (display != NULL) {
523 GLX_Extensions = glXQueryExtensionsString(display, DefaultScreen(display));
524 TRACE_(d3d_caps)("GLX_Extensions reported:\n");
526 if (NULL == GLX_Extensions) {
527 ERR(" GLX_Extensions returns NULL\n");
528 } else {
529 while (*GLX_Extensions != 0x00) {
530 const char *Start = GLX_Extensions;
531 char ThisExtn[256];
533 memset(ThisExtn, 0x00, sizeof(ThisExtn));
534 while (*GLX_Extensions != ' ' && *GLX_Extensions != 0x00) {
535 GLX_Extensions++;
537 memcpy(ThisExtn, Start, (GLX_Extensions - Start));
538 TRACE_(d3d_caps)("- %s\n", ThisExtn);
539 if (*GLX_Extensions == ' ') GLX_Extensions++;
544 #define USE_GL_FUNC(type, pfn) gl_info->pfn = (type) glXGetProcAddressARB(#pfn);
545 GLX_EXT_FUNCS_GEN;
546 #undef USE_GL_FUNC
548 /* Only save the values obtained when a display is provided */
549 if (display != NULL) {
550 return TRUE;
551 } else {
552 return FALSE;
556 /**********************************************************
557 * IWineD3D implementation follows
558 **********************************************************/
560 UINT WINAPI IWineD3DImpl_GetAdapterCount (IWineD3D *iface) {
561 IWineD3DImpl *This = (IWineD3DImpl *)iface;
563 /* FIXME: Set to one for now to imply the display */
564 TRACE_(d3d_caps)("(%p): Mostly stub, only returns primary display\n", This);
565 return 1;
568 HRESULT WINAPI IWineD3DImpl_RegisterSoftwareDevice(IWineD3D *iface, void* pInitializeFunction) {
569 IWineD3DImpl *This = (IWineD3DImpl *)iface;
570 FIXME("(%p)->(%p): stub\n", This, pInitializeFunction);
571 return D3D_OK;
574 HMONITOR WINAPI IWineD3DImpl_GetAdapterMonitor(IWineD3D *iface, UINT Adapter) {
575 IWineD3DImpl *This = (IWineD3DImpl *)iface;
576 FIXME_(d3d_caps)("(%p)->(Adptr:%d)\n", This, Adapter);
577 if (Adapter >= IWineD3DImpl_GetAdapterCount(iface)) {
578 return NULL;
580 return D3D_OK;
583 /* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes
584 of the same bpp but different resolutions */
586 /* Note: dx9 supplies a format. Calls from d3d8 supply D3DFMT_UNKNOWN */
587 UINT WINAPI IWineD3DImpl_GetAdapterModeCount(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format) {
588 IWineD3DImpl *This = (IWineD3DImpl *)iface;
589 TRACE_(d3d_caps)("(%p}->(Adapter: %d, Format: %s)\n", This, Adapter, debug_d3dformat(Format));
591 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
592 return 0;
595 if (Adapter == 0) { /* Display */
596 int i = 0;
597 int j = 0;
598 #if !defined( DEBUG_SINGLE_MODE )
599 DEVMODEW DevModeW;
601 /* Work out the current screen bpp */
602 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
603 int bpp = GetDeviceCaps(hdc, BITSPIXEL);
604 DeleteDC(hdc);
606 while (EnumDisplaySettingsExW(NULL, j, &DevModeW, 0)) {
607 j++;
608 switch (Format)
610 case D3DFMT_UNKNOWN:
611 i++;
612 break;
613 case D3DFMT_X8R8G8B8:
614 case D3DFMT_A8R8G8B8:
615 if (min(DevModeW.dmBitsPerPel, bpp) == 32) i++;
616 if (min(DevModeW.dmBitsPerPel, bpp) == 24) i++;
617 break;
618 case D3DFMT_X1R5G5B5:
619 case D3DFMT_A1R5G5B5:
620 case D3DFMT_R5G6B5:
621 if (min(DevModeW.dmBitsPerPel, bpp) == 16) i++;
622 break;
623 default:
624 /* Skip other modes as they do not match requested format */
625 break;
628 #else
629 i = 1;
630 j = 1;
631 #endif
632 TRACE_(d3d_caps)("(%p}->(Adapter: %d) => %d (out of %d)\n", This, Adapter, i, j);
633 return i;
634 } else {
635 FIXME_(d3d_caps)("Adapter not primary display\n");
637 return 0;
640 /* Note: dx9 supplies a format. Calls from d3d8 supply D3DFMT_UNKNOWN */
641 HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) {
642 IWineD3DImpl *This = (IWineD3DImpl *)iface;
643 TRACE_(d3d_caps)("(%p}->(Adapter:%d, mode:%d, pMode:%p, format:%s)\n", This, Adapter, Mode, pMode, debug_d3dformat(Format));
645 /* Validate the parameters as much as possible */
646 if (NULL == pMode ||
647 Adapter >= IWineD3DImpl_GetAdapterCount(iface) ||
648 Mode >= IWineD3DImpl_GetAdapterModeCount(iface, Adapter, Format)) {
649 return D3DERR_INVALIDCALL;
652 if (Adapter == 0) { /* Display */
653 #if !defined( DEBUG_SINGLE_MODE )
654 DEVMODEW DevModeW;
655 int ModeIdx = 0;
657 /* Work out the current screen bpp */
658 HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
659 int bpp = GetDeviceCaps(hdc, BITSPIXEL);
660 DeleteDC(hdc);
662 /* If we are filtering to a specific format, then need to skip all unrelated
663 modes, but if mode is irrelevant, then we can use the index directly */
664 if (Format == D3DFMT_UNKNOWN)
666 ModeIdx = Mode;
667 } else {
668 int i = 0;
669 int j = 0;
670 DEVMODEW DevModeWtmp;
673 while (i<(Mode+1) && EnumDisplaySettingsExW(NULL, j, &DevModeWtmp, 0)) {
674 j++;
675 switch (Format)
677 case D3DFMT_UNKNOWN:
678 i++;
679 break;
680 case D3DFMT_X8R8G8B8:
681 case D3DFMT_A8R8G8B8:
682 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 32) i++;
683 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 24) i++;
684 break;
685 case D3DFMT_X1R5G5B5:
686 case D3DFMT_A1R5G5B5:
687 case D3DFMT_R5G6B5:
688 if (min(DevModeWtmp.dmBitsPerPel, bpp) == 16) i++;
689 break;
690 default:
691 /* Skip other modes as they do not match requested format */
692 break;
695 ModeIdx = j;
698 /* Now get the display mode via the calculated index */
699 if (EnumDisplaySettingsExW(NULL, ModeIdx, &DevModeW, 0))
701 pMode->Width = DevModeW.dmPelsWidth;
702 pMode->Height = DevModeW.dmPelsHeight;
703 bpp = min(DevModeW.dmBitsPerPel, bpp);
704 pMode->RefreshRate = D3DADAPTER_DEFAULT;
705 if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
707 pMode->RefreshRate = DevModeW.dmDisplayFrequency;
710 if (Format == D3DFMT_UNKNOWN)
712 switch (bpp) {
713 case 8: pMode->Format = D3DFMT_R3G3B2; break;
714 case 16: pMode->Format = D3DFMT_R5G6B5; break;
715 case 24: /* pMode->Format = D3DFMT_R5G6B5; break;*/ /* Make 24bit appear as 32 bit */
716 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
717 default: pMode->Format = D3DFMT_UNKNOWN;
719 } else {
720 pMode->Format = Format;
723 else
725 TRACE_(d3d_caps)("Requested mode out of range %d\n", Mode);
726 return D3DERR_INVALIDCALL;
729 #else
730 /* Return one setting of the format requested */
731 if (Mode > 0) return D3DERR_INVALIDCALL;
732 pMode->Width = 800;
733 pMode->Height = 600;
734 pMode->RefreshRate = D3DADAPTER_DEFAULT;
735 pMode->Format = (Format==D3DFMT_UNKNOWN)?D3DFMT_A8R8G8B8:Format;
736 bpp = 32;
737 #endif
738 TRACE_(d3d_caps)("W %d H %d rr %d fmt (%x - %s) bpp %u\n", pMode->Width, pMode->Height,
739 pMode->RefreshRate, pMode->Format, debug_d3dformat(pMode->Format), bpp);
741 } else {
742 FIXME_(d3d_caps)("Adapter not primary display\n");
745 return D3D_OK;
748 HRESULT WINAPI IWineD3DImpl_GetAdapterDisplayMode(IWineD3D *iface, UINT Adapter, D3DDISPLAYMODE* pMode) {
749 IWineD3DImpl *This = (IWineD3DImpl *)iface;
750 TRACE_(d3d_caps)("(%p}->(Adapter: %d, pMode: %p)\n", This, Adapter, pMode);
752 if (NULL == pMode ||
753 Adapter >= IWineD3D_GetAdapterCount(iface)) {
754 return D3DERR_INVALIDCALL;
757 if (Adapter == 0) { /* Display */
758 int bpp = 0;
759 DEVMODEW DevModeW;
761 EnumDisplaySettingsExW(NULL, (DWORD)-1, &DevModeW, 0);
762 pMode->Width = DevModeW.dmPelsWidth;
763 pMode->Height = DevModeW.dmPelsHeight;
764 bpp = DevModeW.dmBitsPerPel;
765 pMode->RefreshRate = D3DADAPTER_DEFAULT;
766 if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
768 pMode->RefreshRate = DevModeW.dmDisplayFrequency;
771 switch (bpp) {
772 case 8: pMode->Format = D3DFMT_R3G3B2; break;
773 case 16: pMode->Format = D3DFMT_R5G6B5; break;
774 case 24: /*pMode->Format = D3DFMT_R5G6B5; break;*/ /* Make 24bit appear as 32 bit */
775 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
776 default: pMode->Format = D3DFMT_UNKNOWN;
779 } else {
780 FIXME_(d3d_caps)("Adapter not primary display\n");
783 TRACE_(d3d_caps)("returning w:%d, h:%d, ref:%d, fmt:%s\n", pMode->Width,
784 pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
785 return D3D_OK;
788 /* Note due to structure differences between dx8 and dx9 D3DADAPTER_IDENTIFIER,
789 and fields being inserted in the middle, a new structure is used in place */
790 HRESULT WINAPI IWineD3DImpl_GetAdapterIdentifier(IWineD3D *iface, UINT Adapter, DWORD Flags,
791 WINED3DADAPTER_IDENTIFIER* pIdentifier) {
792 IWineD3DImpl *This = (IWineD3DImpl *)iface;
794 TRACE_(d3d_caps)("(%p}->(Adapter: %d, Flags: %lx, pId=%p)\n", This, Adapter, Flags, pIdentifier);
796 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
797 return D3DERR_INVALIDCALL;
800 if (Adapter == 0) { /* Display - only device supported for now */
802 BOOL isGLInfoValid = This->isGLInfoValid;
804 /* FillGLCaps updates gl_info, but we only want to store and
805 reuse the values once we have a context which is valid. Values from
806 a temporary context may differ from the final ones */
807 if (isGLInfoValid == FALSE) {
809 /* If we don't know the device settings, go query them now via a
810 fake context */
811 WineD3D_Context* ctx = WineD3D_CreateFakeGLContext();
812 if (NULL != ctx) {
813 isGLInfoValid = IWineD3DImpl_FillGLCaps(&This->gl_info, ctx->display);
814 WineD3D_ReleaseFakeGLContext(ctx);
818 /* If it worked, return the information requested */
819 if (isGLInfoValid) {
820 TRACE_(d3d_caps)("device/Vendor Name and Version detection using FillGLCaps\n");
821 strcpy(pIdentifier->Driver, "Display");
822 strcpy(pIdentifier->Description, "Direct3D HAL");
824 /* Note dx8 doesn't supply a DeviceName */
825 if (NULL != pIdentifier->DeviceName) strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY"); /* FIXME: May depend on desktop? */
826 pIdentifier->DriverVersion->u.HighPart = 0xa;
827 pIdentifier->DriverVersion->u.LowPart = This->gl_info.gl_driver_version;
828 *(pIdentifier->VendorId) = This->gl_info.gl_vendor;
829 *(pIdentifier->DeviceId) = This->gl_info.gl_card;
830 *(pIdentifier->SubSysId) = 0;
831 *(pIdentifier->Revision) = 0;
833 } else {
835 /* If it failed, return dummy values from an NVidia driver */
836 WARN_(d3d_caps)("Cannot get GLCaps for device/Vendor Name and Version detection using FillGLCaps, currently using NVIDIA identifiers\n");
837 strcpy(pIdentifier->Driver, "Display");
838 strcpy(pIdentifier->Description, "Direct3D HAL");
839 if (NULL != pIdentifier->DeviceName) strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY"); /* FIXME: May depend on desktop? */
840 pIdentifier->DriverVersion->u.HighPart = 0xa;
841 pIdentifier->DriverVersion->u.LowPart = MAKEDWORD_VERSION(53, 96); /* last Linux Nvidia drivers */
842 *(pIdentifier->VendorId) = VENDOR_NVIDIA;
843 *(pIdentifier->DeviceId) = CARD_NVIDIA_GEFORCE4_TI4600;
844 *(pIdentifier->SubSysId) = 0;
845 *(pIdentifier->Revision) = 0;
848 /*FIXME: memcpy(&pIdentifier->DeviceIdentifier, ??, sizeof(??GUID)); */
849 if (Flags & D3DENUM_NO_WHQL_LEVEL) {
850 *(pIdentifier->WHQLLevel) = 0;
851 } else {
852 *(pIdentifier->WHQLLevel) = 1;
855 } else {
856 FIXME_(d3d_caps)("Adapter not primary display\n");
859 return D3D_OK;
862 static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(WineD3D_Context* ctx, GLXFBConfig cfgs, WINED3DFORMAT Format) {
863 int gl_test;
864 int rb, gb, bb, ab, type, buf_sz;
866 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_RED_SIZE, &rb);
867 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_GREEN_SIZE, &gb);
868 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_BLUE_SIZE, &bb);
869 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_ALPHA_SIZE, &ab);
870 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_RENDER_TYPE, &type);
871 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_BUFFER_SIZE, &buf_sz);
873 switch (Format) {
874 case WINED3DFMT_X8R8G8B8:
875 case WINED3DFMT_R8G8B8:
876 if (8 == rb && 8 == gb && 8 == bb) return TRUE;
877 break;
878 case WINED3DFMT_A8R8G8B8:
879 if (8 == rb && 8 == gb && 8 == bb && 8 == ab) return TRUE;
880 break;
881 case WINED3DFMT_X1R5G5B5:
882 if (5 == rb && 5 == gb && 5 == bb) return TRUE;
883 break;
884 case WINED3DFMT_A1R5G5B5:
885 if (5 == rb && 5 == gb && 5 == bb && 1 == ab) return TRUE;
886 break;
887 case WINED3DFMT_R5G6B5:
888 if (5 == rb && 6 == gb && 5 == bb) return TRUE;
889 break;
890 case WINED3DFMT_R3G3B2:
891 if (3 == rb && 3 == gb && 2 == bb) return TRUE;
892 break;
893 case WINED3DFMT_A8P8:
894 if (type & GLX_COLOR_INDEX_BIT && 8 == buf_sz && 8 == ab) return TRUE;
895 break;
896 case WINED3DFMT_P8:
897 if (type & GLX_COLOR_INDEX_BIT && 8 == buf_sz) return TRUE;
898 break;
899 default:
900 ERR("unsupported format %s\n", debug_d3dformat(Format));
901 break;
903 return FALSE;
906 static BOOL IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(WineD3D_Context* ctx, GLXFBConfig cfgs, WINED3DFORMAT Format) {
907 int gl_test;
908 int db, sb;
910 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_DEPTH_SIZE, &db);
911 gl_test = glXGetFBConfigAttrib(ctx->display, cfgs, GLX_STENCIL_SIZE, &sb);
913 switch (Format) {
914 case WINED3DFMT_D16:
915 case WINED3DFMT_D16_LOCKABLE:
916 if (16 == db) return TRUE;
917 break;
918 case WINED3DFMT_D32:
919 if (32 == db) return TRUE;
920 break;
921 case WINED3DFMT_D15S1:
922 if (15 == db) return TRUE;
923 break;
924 case WINED3DFMT_D24S8:
925 if (24 == db && 8 == sb) return TRUE;
926 break;
927 case WINED3DFMT_D24X8:
928 if (24 == db) return TRUE;
929 break;
930 case WINED3DFMT_D24X4S4:
931 if (24 == db && 4 == sb) return TRUE;
932 break;
933 case WINED3DFMT_D32F_LOCKABLE:
934 if (32 == db) return TRUE;
935 break;
936 default:
937 ERR("unsupported format %s\n", debug_d3dformat(Format));
938 break;
940 return FALSE;
943 HRESULT WINAPI IWineD3DImpl_CheckDepthStencilMatch(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType,
944 WINED3DFORMAT AdapterFormat,
945 WINED3DFORMAT RenderTargetFormat,
946 WINED3DFORMAT DepthStencilFormat) {
947 IWineD3DImpl *This = (IWineD3DImpl *)iface;
948 WARN_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), AdptFmt:(%x,%s), RendrTgtFmt:(%x,%s), DepthStencilFmt:(%x,%s))\n",
949 This, Adapter,
950 DeviceType, debug_d3ddevicetype(DeviceType),
951 AdapterFormat, debug_d3dformat(AdapterFormat),
952 RenderTargetFormat, debug_d3dformat(RenderTargetFormat),
953 DepthStencilFormat, debug_d3dformat(DepthStencilFormat));
955 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
956 return D3DERR_INVALIDCALL;
960 GLXFBConfig* cfgs = NULL;
961 int nCfgs = 0;
962 int it;
963 HRESULT hr = D3DERR_NOTAVAILABLE;
965 WineD3D_Context* ctx = WineD3D_CreateFakeGLContext();
966 if (NULL != ctx) {
967 cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
968 for (it = 0; it < nCfgs; ++it) {
969 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx, cfgs[it], RenderTargetFormat)) {
970 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithDepthFmt(ctx, cfgs[it], DepthStencilFormat)) {
971 hr = D3D_OK;
972 break ;
976 XFree(cfgs);
978 WineD3D_ReleaseFakeGLContext(ctx);
979 return hr;
983 return D3DERR_NOTAVAILABLE;
986 HRESULT WINAPI IWineD3DImpl_CheckDeviceMultiSampleType(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType,
987 WINED3DFORMAT SurfaceFormat,
988 BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) {
990 IWineD3DImpl *This = (IWineD3DImpl *)iface;
991 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), SurfFmt:(%x,%s), Win?%d, MultiSamp:%x, pQual:%p)\n",
992 This,
993 Adapter,
994 DeviceType, debug_d3ddevicetype(DeviceType),
995 SurfaceFormat, debug_d3dformat(SurfaceFormat),
996 Windowed,
997 MultiSampleType,
998 pQualityLevels);
1000 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1001 return D3DERR_INVALIDCALL;
1004 if (pQualityLevels != NULL) {
1005 static int s_single_shot = 0;
1006 if (!s_single_shot) {
1007 FIXME("Quality levels unsupported at present\n");
1008 s_single_shot = 1;
1010 *pQualityLevels = 1; /* Guess at a value! */
1013 if (D3DMULTISAMPLE_NONE == MultiSampleType) return D3D_OK;
1014 return D3DERR_NOTAVAILABLE;
1017 HRESULT WINAPI IWineD3DImpl_CheckDeviceType(IWineD3D *iface, UINT Adapter, D3DDEVTYPE CheckType,
1018 WINED3DFORMAT DisplayFormat, WINED3DFORMAT BackBufferFormat, BOOL Windowed) {
1020 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1021 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, CheckType:(%x,%s), DispFmt:(%x,%s), BackBuf:(%x,%s), Win?%d): stub\n",
1022 This,
1023 Adapter,
1024 CheckType, debug_d3ddevicetype(CheckType),
1025 DisplayFormat, debug_d3dformat(DisplayFormat),
1026 BackBufferFormat, debug_d3dformat(BackBufferFormat),
1027 Windowed);
1029 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1030 return D3DERR_INVALIDCALL;
1034 GLXFBConfig* cfgs = NULL;
1035 int nCfgs = 0;
1036 int it;
1037 HRESULT hr = D3DERR_NOTAVAILABLE;
1039 WineD3D_Context* ctx = WineD3D_CreateFakeGLContext();
1040 if (NULL != ctx) {
1041 cfgs = glXGetFBConfigs(ctx->display, DefaultScreen(ctx->display), &nCfgs);
1042 for (it = 0; it < nCfgs; ++it) {
1043 if (IWineD3DImpl_IsGLXFBConfigCompatibleWithRenderFmt(ctx, cfgs[it], DisplayFormat)) {
1044 hr = D3D_OK;
1045 break ;
1048 XFree(cfgs);
1050 WineD3D_ReleaseFakeGLContext(ctx);
1051 return hr;
1055 return D3DERR_NOTAVAILABLE;
1058 HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType,
1059 WINED3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat) {
1060 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1061 TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), AdptFmt:(%u,%s), Use:(%lu,%s), ResTyp:(%x,%s), CheckFmt:(%u,%s)) ",
1062 This,
1063 Adapter,
1064 DeviceType, debug_d3ddevicetype(DeviceType),
1065 AdapterFormat, debug_d3dformat(AdapterFormat),
1066 Usage, debug_d3dusage(Usage),
1067 RType, debug_d3dresourcetype(RType),
1068 CheckFormat, debug_d3dformat(CheckFormat));
1070 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1071 return D3DERR_INVALIDCALL;
1074 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1075 switch (CheckFormat) {
1076 case D3DFMT_DXT1:
1077 case D3DFMT_DXT3:
1078 case D3DFMT_DXT5:
1079 TRACE_(d3d_caps)("[OK]\n");
1080 return D3D_OK;
1081 default:
1082 break; /* Avoid compiler warnings */
1086 switch (CheckFormat) {
1087 /*****
1088 * check supported using GL_SUPPORT
1090 case D3DFMT_DXT1:
1091 case D3DFMT_DXT2:
1092 case D3DFMT_DXT3:
1093 case D3DFMT_DXT4:
1094 case D3DFMT_DXT5:
1096 /*****
1097 * supported
1099 /*case D3DFMT_R5G6B5: */
1100 /*case D3DFMT_X1R5G5B5:*/
1101 /*case D3DFMT_A1R5G5B5: */
1102 /*case D3DFMT_A4R4G4B4:*/
1104 /*****
1105 * unsupported
1108 /* color buffer */
1109 /*case D3DFMT_X8R8G8B8:*/
1110 case D3DFMT_A8R3G3B2:
1112 /* Paletted */
1113 case D3DFMT_P8:
1114 case D3DFMT_A8P8:
1116 /* Luminance */
1117 case D3DFMT_L8:
1118 case D3DFMT_A8L8:
1119 case D3DFMT_A4L4:
1121 /* Bump */
1122 #if 0
1123 case D3DFMT_V8U8:
1124 case D3DFMT_V16U16:
1125 #endif
1126 case D3DFMT_L6V5U5:
1127 case D3DFMT_X8L8V8U8:
1128 case D3DFMT_Q8W8V8U8:
1129 case D3DFMT_W11V11U10:
1131 /****
1132 * currently hard to support
1134 case D3DFMT_UYVY:
1135 case D3DFMT_YUY2:
1137 /* Since we do not support these formats right now, don't pretend to. */
1138 TRACE_(d3d_caps)("[FAILED]\n");
1139 return D3DERR_NOTAVAILABLE;
1140 default:
1141 break;
1144 TRACE_(d3d_caps)("[OK]\n");
1145 return D3D_OK;
1148 HRESULT WINAPI IWineD3DImpl_CheckDeviceFormatConversion(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType,
1149 WINED3DFORMAT SourceFormat, WINED3DFORMAT TargetFormat) {
1150 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1152 FIXME_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), SrcFmt:(%u,%s), TgtFmt:(%u,%s))",
1153 This,
1154 Adapter,
1155 DeviceType, debug_d3ddevicetype(DeviceType),
1156 SourceFormat, debug_d3dformat(SourceFormat),
1157 TargetFormat, debug_d3dformat(TargetFormat));
1158 return D3D_OK;
1161 /* Note: d3d8 passes in a pointer to a D3DCAPS8 structure, which is a true
1162 subset of a D3DCAPS9 structure. However, it has to come via a void *
1163 as the d3d8 interface cannot import the d3d9 header */
1164 HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType, WINED3DCAPS* pCaps) {
1166 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1167 BOOL gotContext = FALSE;
1168 GLint gl_tex_size = 0;
1169 WineD3D_Context *fake_ctx = NULL;
1171 TRACE_(d3d_caps)("(%p)->(Adptr:%d, DevType: %x, pCaps: %p)\n", This, Adapter, DeviceType, pCaps);
1173 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1174 return D3DERR_INVALIDCALL;
1177 /* Note: GL seems to trap if GetDeviceCaps is called before any HWND's created
1178 ie there is no GL Context - Get a default rendering context to enable the
1179 function query some info from GL */
1180 if (glXGetCurrentContext() == NULL) {
1181 fake_ctx = WineD3D_CreateFakeGLContext();
1182 if (NULL != fake_ctx) gotContext = TRUE;
1183 } else {
1184 gotContext = TRUE;
1187 if (gotContext == FALSE) {
1189 FIXME_(d3d_caps)("GetDeviceCaps called but no GL Context - Returning dummy values\n");
1190 gl_tex_size=65535;
1191 *(pCaps->MaxTextureBlendStages) = 2;
1192 *pCaps->MaxSimultaneousTextures = 2;
1193 *pCaps->MaxUserClipPlanes = 8;
1194 *pCaps->MaxActiveLights = 8;
1195 *pCaps->MaxVertexBlendMatrices = 0;
1196 *pCaps->MaxVertexBlendMatrixIndex = 1;
1197 *pCaps->MaxAnisotropy = 0;
1198 *pCaps->MaxPointSize = 255.0;
1200 } else {
1201 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_tex_size);
1204 /* If we don't know the device settings, go query them now */
1205 if (This->isGLInfoValid == FALSE) {
1206 BOOL rc = IWineD3DImpl_FillGLCaps(&This->gl_info, NULL);
1208 /* If we are running off a real context, save the values */
1209 if (rc && ((NULL != fake_ctx))) This->isGLInfoValid = TRUE;
1212 /* ------------------------------------------------
1213 The following fields apply to both d3d8 and d3d9
1214 ------------------------------------------------ */
1215 *pCaps->DeviceType = (DeviceType == D3DDEVTYPE_HAL) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; /* Not quite true, but use h/w supported by opengl I suppose */
1216 *pCaps->AdapterOrdinal = Adapter;
1218 *pCaps->Caps = 0;
1219 *pCaps->Caps2 = D3DCAPS2_CANRENDERWINDOWED;
1220 *pCaps->Caps3 = D3DDEVCAPS_HWTRANSFORMANDLIGHT;
1221 *pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_IMMEDIATE;
1223 *pCaps->CursorCaps = 0;
1226 *pCaps->DevCaps = D3DDEVCAPS_DRAWPRIMTLVERTEX |
1227 D3DDEVCAPS_HWTRANSFORMANDLIGHT |
1228 D3DDEVCAPS_PUREDEVICE |
1229 D3DDEVCAPS_HWRASTERIZATION;
1232 *pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_CULLCCW |
1233 D3DPMISCCAPS_CULLCW |
1234 D3DPMISCCAPS_COLORWRITEENABLE |
1235 D3DPMISCCAPS_CLIPTLVERTS |
1236 D3DPMISCCAPS_CLIPPLANESCALEDPOINTS |
1237 D3DPMISCCAPS_MASKZ;
1238 /*NOT: D3DPMISCCAPS_TSSARGTEMP*/
1240 *pCaps->RasterCaps = D3DPRASTERCAPS_DITHER |
1241 D3DPRASTERCAPS_PAT |
1242 D3DPRASTERCAPS_WFOG |
1243 D3DPRASTERCAPS_ZFOG |
1244 D3DPRASTERCAPS_FOGVERTEX |
1245 D3DPRASTERCAPS_FOGTABLE |
1246 D3DPRASTERCAPS_FOGRANGE;
1248 if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
1249 *pCaps->RasterCaps |= D3DPRASTERCAPS_ANISOTROPY |
1250 D3DPRASTERCAPS_ZBIAS |
1251 D3DPRASTERCAPS_MIPMAPLODBIAS;
1253 /* FIXME Add:
1254 D3DPRASTERCAPS_COLORPERSPECTIVE
1255 D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE
1256 D3DPRASTERCAPS_ANTIALIASEDGES
1257 D3DPRASTERCAPS_ZBUFFERLESSHSR
1258 D3DPRASTERCAPS_WBUFFER */
1260 *pCaps->ZCmpCaps = D3DPCMPCAPS_ALWAYS |
1261 D3DPCMPCAPS_EQUAL |
1262 D3DPCMPCAPS_GREATER |
1263 D3DPCMPCAPS_GREATEREQUAL |
1264 D3DPCMPCAPS_LESS |
1265 D3DPCMPCAPS_LESSEQUAL |
1266 D3DPCMPCAPS_NEVER |
1267 D3DPCMPCAPS_NOTEQUAL;
1269 *pCaps->SrcBlendCaps = 0xFFFFFFFF; /*FIXME: Tidy up later */
1270 *pCaps->DestBlendCaps = 0xFFFFFFFF; /*FIXME: Tidy up later */
1271 *pCaps->AlphaCmpCaps = 0xFFFFFFFF; /*FIXME: Tidy up later */
1273 *pCaps->ShadeCaps = D3DPSHADECAPS_SPECULARGOURAUDRGB |
1274 D3DPSHADECAPS_COLORGOURAUDRGB;
1276 *pCaps->TextureCaps = D3DPTEXTURECAPS_ALPHA |
1277 D3DPTEXTURECAPS_ALPHAPALETTE |
1278 D3DPTEXTURECAPS_VOLUMEMAP |
1279 D3DPTEXTURECAPS_MIPMAP |
1280 D3DPTEXTURECAPS_PROJECTED |
1281 D3DPTEXTURECAPS_PERSPECTIVE |
1282 D3DPTEXTURECAPS_VOLUMEMAP_POW2 ;
1283 /* TODO: add support for NON-POW2 if avaialble
1286 if (This->dxVersion > 8) {
1287 *pCaps->TextureCaps |= D3DPTEXTURECAPS_NONPOW2CONDITIONAL;
1289 } else { /* NONPOW2 isn't accessable by d3d8 yet */
1290 *pCaps->TextureCaps |= D3DPTEXTURECAPS_POW2;
1293 if (GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) {
1294 *pCaps->TextureCaps |= D3DPTEXTURECAPS_CUBEMAP |
1295 D3DPTEXTURECAPS_MIPCUBEMAP |
1296 D3DPTEXTURECAPS_CUBEMAP_POW2;
1300 *pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MAGFLINEAR |
1301 D3DPTFILTERCAPS_MAGFPOINT |
1302 D3DPTFILTERCAPS_MINFLINEAR |
1303 D3DPTFILTERCAPS_MINFPOINT |
1304 D3DPTFILTERCAPS_MIPFLINEAR |
1305 D3DPTFILTERCAPS_MIPFPOINT;
1307 *pCaps->CubeTextureFilterCaps = 0;
1308 *pCaps->VolumeTextureFilterCaps = 0;
1310 *pCaps->TextureAddressCaps = D3DPTADDRESSCAPS_BORDER |
1311 D3DPTADDRESSCAPS_CLAMP |
1312 D3DPTADDRESSCAPS_WRAP;
1314 if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) {
1315 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_BORDER;
1317 if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) {
1318 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
1320 if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) {
1321 *pCaps->TextureAddressCaps |= D3DPTADDRESSCAPS_MIRRORONCE;
1324 *pCaps->VolumeTextureAddressCaps = 0;
1326 *pCaps->LineCaps = D3DLINECAPS_TEXTURE |
1327 D3DLINECAPS_ZTEST;
1328 /* FIXME: Add
1329 D3DLINECAPS_BLEND
1330 D3DLINECAPS_ALPHACMP
1331 D3DLINECAPS_FOG */
1333 *pCaps->MaxTextureWidth = gl_tex_size;
1334 *pCaps->MaxTextureHeight = gl_tex_size;
1336 *pCaps->MaxVolumeExtent = 0;
1338 *pCaps->MaxTextureRepeat = 32768;
1339 *pCaps->MaxTextureAspectRatio = 32768;
1340 *pCaps->MaxVertexW = 1.0;
1342 *pCaps->GuardBandLeft = 0;
1343 *pCaps->GuardBandTop = 0;
1344 *pCaps->GuardBandRight = 0;
1345 *pCaps->GuardBandBottom = 0;
1347 *pCaps->ExtentsAdjust = 0;
1349 *pCaps->StencilCaps = D3DSTENCILCAPS_DECRSAT |
1350 D3DSTENCILCAPS_INCRSAT |
1351 D3DSTENCILCAPS_INVERT |
1352 D3DSTENCILCAPS_KEEP |
1353 D3DSTENCILCAPS_REPLACE |
1354 D3DSTENCILCAPS_ZERO;
1355 if (GL_SUPPORT(EXT_STENCIL_WRAP)) {
1356 *pCaps->StencilCaps |= D3DSTENCILCAPS_DECR |
1357 D3DSTENCILCAPS_INCR;
1360 *pCaps->FVFCaps = D3DFVFCAPS_PSIZE | 0x0008; /* 8 texture coords */
1362 *pCaps->TextureOpCaps = D3DTEXOPCAPS_ADD |
1363 D3DTEXOPCAPS_ADDSIGNED |
1364 D3DTEXOPCAPS_ADDSIGNED2X |
1365 D3DTEXOPCAPS_MODULATE |
1366 D3DTEXOPCAPS_MODULATE2X |
1367 D3DTEXOPCAPS_MODULATE4X |
1368 D3DTEXOPCAPS_SELECTARG1 |
1369 D3DTEXOPCAPS_SELECTARG2 |
1370 D3DTEXOPCAPS_DISABLE;
1371 #if defined(GL_VERSION_1_3)
1372 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_DOTPRODUCT3 |
1373 D3DTEXOPCAPS_SUBTRACT;
1374 #endif
1375 if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE) ||
1376 GL_SUPPORT(EXT_TEXTURE_ENV_COMBINE) ||
1377 GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
1378 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_BLENDDIFFUSEALPHA |
1379 D3DTEXOPCAPS_BLENDTEXTUREALPHA |
1380 D3DTEXOPCAPS_BLENDFACTORALPHA |
1381 D3DTEXOPCAPS_BLENDCURRENTALPHA |
1382 D3DTEXOPCAPS_LERP;
1384 if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
1385 *pCaps->TextureOpCaps |= D3DTEXOPCAPS_ADDSMOOTH |
1386 D3DTEXOPCAPS_MULTIPLYADD |
1387 D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR |
1388 D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
1389 D3DTEXOPCAPS_BLENDTEXTUREALPHAPM;
1392 #if 0
1393 pCaps->TextureOpCaps |= D3DTEXOPCAPS_BUMPENVMAP;
1394 /* FIXME: Add
1395 D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
1396 D3DTEXOPCAPS_PREMODULATE */
1397 #endif
1399 if (gotContext) {
1400 GLint gl_max;
1401 GLfloat gl_float;
1402 #if defined(GL_VERSION_1_3)
1403 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &gl_max);
1404 #else
1405 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_max);
1406 #endif
1407 TRACE_(d3d_caps)("GLCaps: GL_MAX_TEXTURE_UNITS_ARB=%d\n", gl_max);
1408 *pCaps->MaxTextureBlendStages = min(8, gl_max);
1409 *pCaps->MaxSimultaneousTextures = min(8, gl_max);
1411 glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_max);
1412 *pCaps->MaxUserClipPlanes = min(D3DMAXUSERCLIPPLANES, gl_max);
1413 TRACE_(d3d_caps)("GLCaps: GL_MAX_CLIP_PLANES=%ld\n", *pCaps->MaxUserClipPlanes);
1415 glGetIntegerv(GL_MAX_LIGHTS, &gl_max);
1416 *pCaps->MaxActiveLights = gl_max;
1417 TRACE_(d3d_caps)("GLCaps: GL_MAX_LIGHTS=%ld\n", *pCaps->MaxActiveLights);
1419 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
1420 glGetIntegerv(GL_MAX_VERTEX_UNITS_ARB, &gl_max);
1421 #if 0 /* TODO : add support for blends to drawprim */
1422 *pCaps->MaxVertexBlendMatrices = gl_max;
1423 #else
1424 *pCaps->MaxVertexBlendMatrices = 0;
1425 #endif
1426 *pCaps->MaxVertexBlendMatrixIndex = 1;
1427 } else {
1428 *pCaps->MaxVertexBlendMatrices = 0;
1429 *pCaps->MaxVertexBlendMatrixIndex = 1;
1432 if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
1433 glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max);
1434 *pCaps->MaxAnisotropy = gl_max;
1435 } else {
1436 *pCaps->MaxAnisotropy = 0;
1439 glGetFloatv(GL_POINT_SIZE_RANGE, &gl_float);
1440 *pCaps->MaxPointSize = gl_float;
1443 *pCaps->VertexProcessingCaps = D3DVTXPCAPS_DIRECTIONALLIGHTS |
1444 D3DVTXPCAPS_MATERIALSOURCE7 |
1445 D3DVTXPCAPS_POSITIONALLIGHTS |
1446 D3DVTXPCAPS_LOCALVIEWER |
1447 D3DVTXPCAPS_TEXGEN;
1448 /* FIXME: Add
1449 D3DVTXPCAPS_TWEENING */
1451 *pCaps->MaxPrimitiveCount = 0xFFFFFFFF;
1452 *pCaps->MaxVertexIndex = 0xFFFFFFFF;
1453 *pCaps->MaxStreams = MAX_STREAMS;
1454 *pCaps->MaxStreamStride = 1024;
1456 if (((vs_mode == VS_HW) && GL_SUPPORT(ARB_VERTEX_PROGRAM)) || (vs_mode == VS_SW) || (DeviceType == D3DDEVTYPE_REF)) {
1457 *pCaps->VertexShaderVersion = D3DVS_VERSION(1,1);
1459 if (This->gl_info.gl_vendor == VENDOR_MESA ||
1460 This->gl_info.gl_vendor == VENDOR_WINE) {
1461 *pCaps->MaxVertexShaderConst = 95;
1462 } else {
1463 *pCaps->MaxVertexShaderConst = WINED3D_VSHADER_MAX_CONSTANTS;
1465 } else {
1466 *pCaps->VertexShaderVersion = 0;
1467 *pCaps->MaxVertexShaderConst = 0;
1470 if ((ps_mode == PS_HW) && GL_SUPPORT(ARB_FRAGMENT_PROGRAM) && (DeviceType != D3DDEVTYPE_REF)) {
1471 *pCaps->PixelShaderVersion = D3DPS_VERSION(1,4);
1472 *pCaps->PixelShader1xMaxValue = 1.0;
1473 } else {
1474 *pCaps->PixelShaderVersion = 0;
1475 *pCaps->PixelShader1xMaxValue = 0.0;
1477 /* TODO: ARB_FRAGMENT_PROGRAM_100 */
1479 /* ------------------------------------------------
1480 The following fields apply to d3d9 only
1481 ------------------------------------------------ */
1482 if (This->dxVersion > 8) {
1483 GLint max_buffers=1;
1484 FIXME("Caps support for directx9 is nonexistent at the moment!\n");
1485 *pCaps->DevCaps2 = 0;
1486 /* TODO: D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES */
1487 *pCaps->MaxNpatchTessellationLevel = 0;
1488 *pCaps->MasterAdapterOrdinal = 0;
1489 *pCaps->AdapterOrdinalInGroup = 0;
1490 *pCaps->NumberOfAdaptersInGroup = 1;
1491 *pCaps->DeclTypes = 0;
1492 #if 0 /*FIXME: Simultaneous render targets*/
1493 GL_MAX_DRAW_BUFFERS_ATI 0x00008824
1494 if (GL_SUPPORT(GL_MAX_DRAW_BUFFERS_ATI)) {
1495 ENTER_GL();
1496 glEnable(GL_MAX_DRAW_BUFFERS_ATI);
1497 glGetIntegerv(GL_MAX_DRAW_BUFFERS_ATI, &max_buffers);
1498 glDisable(GL_MAX_DRAW_BUFFERS_ATI);
1499 LEAVE_GL();
1501 #endif
1502 *pCaps->NumSimultaneousRTs = max_buffers;
1503 *pCaps->StretchRectFilterCaps = 0;
1504 /* TODO: add
1505 D3DPTFILTERCAPS_MINFPOINT
1506 D3DPTFILTERCAPS_MAGFPOINT
1507 D3DPTFILTERCAPS_MINFLINEAR
1508 D3DPTFILTERCAPS_MAGFLINEAR
1510 *pCaps->VS20Caps.Caps = 0;
1511 *pCaps->PS20Caps.Caps = 0;
1512 *pCaps->VertexTextureFilterCaps = 0;
1513 *pCaps->MaxVShaderInstructionsExecuted = 0;
1514 *pCaps->MaxPShaderInstructionsExecuted = 0;
1515 *pCaps->MaxVertexShader30InstructionSlots = 0;
1516 *pCaps->MaxPixelShader30InstructionSlots = 0;
1519 /* If we created a dummy context, throw it away */
1520 if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx);
1521 return D3D_OK;
1525 /* Note due to structure differences between dx8 and dx9 D3DPRESENT_PARAMETERS,
1526 and fields being inserted in the middle, a new structure is used in place */
1527 HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow,
1528 DWORD BehaviourFlags, WINED3DPRESENT_PARAMETERS* pPresentationParameters,
1529 IWineD3DDevice** ppReturnedDeviceInterface, IUnknown *parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget) {
1531 HWND whichHWND;
1532 HDC hDc;
1533 IWineD3DDeviceImpl *object = NULL;
1534 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1535 int num;
1536 XVisualInfo template;
1537 HRESULT res;
1539 /* Validate the adapter number */
1540 if (Adapter >= IWineD3D_GetAdapterCount(iface)) {
1541 return D3DERR_INVALIDCALL;
1544 /* Create a WineD3DDevice object */
1545 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DDeviceImpl));
1546 *ppReturnedDeviceInterface = (IWineD3DDevice *)object;
1547 TRACE("Created WineD3DDevice object @ %p \n", object);
1548 if (NULL == object) {
1549 return D3DERR_OUTOFVIDEOMEMORY;
1552 /* Set up initial COM information */
1553 object->lpVtbl = &IWineD3DDevice_Vtbl;
1554 object->ref = 1;
1555 object->wineD3D = iface;
1556 IWineD3D_AddRef(object->wineD3D);
1557 object->parent = parent;
1559 TRACE("(%p)->(Adptr:%d, DevType: %x, FocusHwnd: %p, BehFlags: %lx, PresParms: %p, RetDevInt: %p)\n", This, Adapter, DeviceType,
1560 hFocusWindow, BehaviourFlags, pPresentationParameters, ppReturnedDeviceInterface);
1561 TRACE("(%p)->(DepthStencil:(%u,%s), BackBufferFormat:(%u,%s))\n", This,
1562 *(pPresentationParameters->AutoDepthStencilFormat), debug_d3dformat(*(pPresentationParameters->AutoDepthStencilFormat)),
1563 *(pPresentationParameters->BackBufferFormat), debug_d3dformat(*(pPresentationParameters->BackBufferFormat)));
1565 /* Save the creation parameters */
1566 object->createParms.AdapterOrdinal = Adapter;
1567 object->createParms.DeviceType = DeviceType;
1568 object->createParms.hFocusWindow = hFocusWindow;
1569 object->createParms.BehaviorFlags = BehaviourFlags;
1571 /* Initialize other useful values */
1572 object->presentParms.BackBufferCount = 1; /* Opengl only supports one? */
1573 object->adapterNo = Adapter;
1574 object->devType = DeviceType;
1576 /* Setup hwnd we are using, plus which display this equates to */
1577 whichHWND = *(pPresentationParameters->hDeviceWindow);
1578 if (!whichHWND) {
1579 whichHWND = hFocusWindow;
1581 object->win_handle = whichHWND;
1582 object->win = (Window)GetPropA( whichHWND, "__wine_x11_whole_window" );
1583 hDc = GetDC(whichHWND);
1584 object->display = get_display(hDc);
1585 ReleaseDC(whichHWND, hDc);
1587 /* FIXME: Use for dx8 code eventually too! */
1588 /* Deliberately no indentation here, as this if will be removed when dx8 support merged in */
1589 if (This->dxVersion > 8) {
1591 /* Create a context based off the properties of the existing visual */
1592 /* Note the visual is chosen as the window is created and the glcontext cannot
1593 use different properties after that point in time. FIXME: How to handle when requested format
1594 doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1595 it chooses is identical to the one already being used! */
1596 /* FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat */
1597 ENTER_GL();
1598 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1599 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1600 if (NULL == object->visInfo) {
1601 ERR("cannot really get XVisual\n");
1602 LEAVE_GL();
1603 return D3DERR_NOTAVAILABLE;
1605 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1606 if (NULL == object->glCtx) {
1607 ERR("cannot create glxContext\n");
1608 LEAVE_GL();
1609 return D3DERR_NOTAVAILABLE;
1611 LEAVE_GL();
1613 if (object->glCtx == NULL) {
1614 ERR("Error in context creation !\n");
1615 return D3DERR_INVALIDCALL;
1616 } else {
1617 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1618 whichHWND, object->glCtx, object->win, object->visInfo);
1621 /* If not windowed, need to go fullscreen, and resize the HWND to the appropriate */
1622 /* dimensions */
1623 if (!*(pPresentationParameters->Windowed)) {
1625 DEVMODEW devmode;
1626 HDC hdc;
1627 int bpp = 0;
1629 /* Get info on the current display setup */
1630 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1631 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1632 DeleteDC(hdc);
1634 /* Change the display settings */
1635 memset(&devmode, 0, sizeof(DEVMODEW));
1636 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1637 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /*Stupid XVidMode cannot change bpp D3DFmtGetBpp(object, pPresentationParameters->BackBufferFormat);*/
1638 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1639 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1640 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1641 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1643 /* Make popup window */
1644 SetWindowLongA(whichHWND, GWL_STYLE, WS_POPUP);
1645 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1646 *(pPresentationParameters->BackBufferWidth),
1647 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1650 /* MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1651 then the corresponding dimension of the client area of the hDeviceWindow
1652 (or the focus window, if hDeviceWindow is NULL) is taken. */
1653 if (*(pPresentationParameters->Windowed) &&
1654 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1655 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1657 RECT Rect;
1658 GetClientRect(whichHWND, &Rect);
1660 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1661 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1662 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1664 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1665 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1666 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1670 /* Save the presentation parms now filled in correctly */
1671 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1672 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1673 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1674 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1675 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1676 object->presentParms.MultiSampleQuality = *(pPresentationParameters->MultiSampleQuality);
1677 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1678 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1679 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1680 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1681 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1682 object->presentParms.Flags = *(pPresentationParameters->Flags);
1683 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1684 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1686 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1687 IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)object,
1688 (D3DSTATEBLOCKTYPE) 0,
1689 (IWineD3DStateBlock **)&object->stateBlock,
1690 NULL); /* Note: No parent needed for initial internal stateblock */
1691 object->updateStateBlock = object->stateBlock;
1693 /* Setup surfaces for the backbuffer, frontbuffer and depthstencil buffer */
1694 TRACE("Creating initial device surfaces\n");
1696 /* We need to 'magic' either d3d8 or d3d9 surfaces for the front and backbuuffer
1697 but the respective CreateRenderTarget functions take a differing number of
1698 parms. Fix this by passing in a function to call which takes identical parms
1699 and handles the differences at the d3dx layer, and returns the IWineD3DSurface
1700 pointer rather than the created D3D8/9 one */
1701 if ((res = D3DCB_CreateRenderTarget((IUnknown *) parent,
1702 *(pPresentationParameters->BackBufferWidth),
1703 *(pPresentationParameters->BackBufferHeight),
1704 *(pPresentationParameters->BackBufferFormat),
1705 *(pPresentationParameters->MultiSampleType),
1706 *(pPresentationParameters->MultiSampleQuality),
1707 TRUE,
1708 (IWineD3DSurface **) &object->frontBuffer,
1709 NULL) != D3D_OK) ||
1710 (res = D3DCB_CreateRenderTarget((IUnknown *) parent,
1711 *(pPresentationParameters->BackBufferWidth),
1712 *(pPresentationParameters->BackBufferHeight),
1713 *(pPresentationParameters->BackBufferFormat),
1714 *(pPresentationParameters->MultiSampleType),
1715 *(pPresentationParameters->MultiSampleQuality),
1716 TRUE,
1717 (IWineD3DSurface **) &object->backBuffer,
1718 NULL) != D3D_OK))
1720 ERR("D3DCB_CreateRenderTarget() failed\n");
1721 return res;
1724 /* TODO:
1725 if (*(pPresentationParameters->EnableAutoDepthStencil)) {
1726 IWineD3DDevice_CreateDepthStencilSurface((IWineD3DDevice *) object,
1727 *(pPresentationParameters->BackBufferWidth),
1728 *(pPresentationParameters->BackBufferHeight),
1729 *(pPresentationParameters->AutoDepthStencilFormat,
1730 D3DMULTISAMPLE_NONE,
1731 (IWineD3DSurface *) &object->depthStencilBuffer);
1732 } else {
1733 object->depthStencilBuffer = NULL;
1735 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil @ %p\n",object->frontBuffer, object->backBuffer, object->depthStencilBuffer);
1738 /* init the default renderTarget management */
1739 object->drawable = object->win;
1740 object->render_ctx = object->glCtx;
1741 object->renderTarget = object->backBuffer;
1743 IWineD3DSurface_AddRef((IWineD3DSurface *) object->renderTarget);
1744 /* TODO: Depth Stencil support
1745 object->stencilBufferTarget = object->depthStencilBuffer;
1746 if (NULL != object->stencilBufferTarget) {
1747 IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) object->stencilBufferTarget);
1751 /* Set up some starting GL setup */
1752 ENTER_GL();
1754 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1755 ERR("Error in setting current context (context %p drawable %ld)!\n", object->glCtx, object->win);
1757 checkGLcall("glXMakeCurrent");
1759 /* Clear the screen */
1760 glClearColor(1.0, 0.0, 0.0, 0.0);
1761 checkGLcall("glClearColor");
1762 glColor3f(1.0, 1.0, 1.0);
1763 checkGLcall("glColor3f");
1765 glEnable(GL_LIGHTING);
1766 checkGLcall("glEnable");
1768 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1769 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1771 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1772 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1774 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1775 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1778 * Initialize openGL extension related variables
1779 * with Default values
1781 This->isGLInfoValid = IWineD3DImpl_FillGLCaps(&This->gl_info, object->display);
1783 /* Setup all the devices defaults */
1784 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)object->stateBlock);
1786 LEAVE_GL();
1788 { /* Set a default viewport */
1789 D3DVIEWPORT9 vp;
1790 vp.X = 0;
1791 vp.Y = 0;
1792 vp.Width = *(pPresentationParameters->BackBufferWidth);
1793 vp.Height = *(pPresentationParameters->BackBufferHeight);
1794 vp.MinZ = 0.0f;
1795 vp.MaxZ = 1.0f;
1796 IWineD3DDevice_SetViewport((IWineD3DDevice *)object, &vp);
1799 /* Initialize the current view state */
1800 object->modelview_valid = 1;
1801 object->proj_valid = 0;
1802 object->view_ident = 1;
1803 object->last_was_rhw = 0;
1804 glGetIntegerv(GL_MAX_LIGHTS, &object->maxConcurrentLights);
1805 TRACE("(%p,%d) All defaults now set up, leaving CreateDevice with %p\n", This, Adapter, object);
1807 /* Clear the screen */
1808 IWineD3DDevice_Clear((IWineD3DDevice *) object, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
1810 } /* End of FIXME: remove when dx8 merged in */
1812 return D3D_OK;
1815 HRESULT WINAPI IWineD3DImpl_GetParent(IWineD3D *iface, IUnknown **pParent) {
1816 IWineD3DImpl *This = (IWineD3DImpl *)iface;
1817 IUnknown_AddRef(This->parent);
1818 *pParent = This->parent;
1819 return D3D_OK;
1822 /**********************************************************
1823 * IWineD3D VTbl follows
1824 **********************************************************/
1826 const IWineD3DVtbl IWineD3D_Vtbl =
1828 IWineD3DImpl_QueryInterface,
1829 IWineD3DImpl_AddRef,
1830 IWineD3DImpl_Release,
1831 IWineD3DImpl_GetParent,
1832 IWineD3DImpl_GetAdapterCount,
1833 IWineD3DImpl_RegisterSoftwareDevice,
1834 IWineD3DImpl_GetAdapterMonitor,
1835 IWineD3DImpl_GetAdapterModeCount,
1836 IWineD3DImpl_EnumAdapterModes,
1837 IWineD3DImpl_GetAdapterDisplayMode,
1838 IWineD3DImpl_GetAdapterIdentifier,
1839 IWineD3DImpl_CheckDeviceMultiSampleType,
1840 IWineD3DImpl_CheckDepthStencilMatch,
1841 IWineD3DImpl_CheckDeviceType,
1842 IWineD3DImpl_CheckDeviceFormat,
1843 IWineD3DImpl_CheckDeviceFormatConversion,
1844 IWineD3DImpl_GetDeviceCaps,
1845 IWineD3DImpl_CreateDevice