wined3d: Separate stream sources and vertex declaration.
[wine/multimedia.git] / dlls / wined3d / context.c
blob3af69e895eff32963439aaaa04ea9304d1d39058
1 /*
2 * Context and render target management in wined3d
4 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
5 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include <stdio.h>
24 #ifdef HAVE_FLOAT_H
25 # include <float.h>
26 #endif
27 #include "wined3d_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
31 static DWORD wined3d_context_tls_idx;
33 /* FBO helper functions */
35 /* GL locking is done by the caller */
36 void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint *fbo)
38 const struct wined3d_gl_info *gl_info = context->gl_info;
39 GLuint f;
41 if (!fbo)
43 f = 0;
45 else
47 if (!*fbo)
49 gl_info->fbo_ops.glGenFramebuffers(1, fbo);
50 checkGLcall("glGenFramebuffers()");
51 TRACE("Created FBO %u.\n", *fbo);
53 f = *fbo;
56 switch (target)
58 case GL_READ_FRAMEBUFFER:
59 if (context->fbo_read_binding == f) return;
60 context->fbo_read_binding = f;
61 break;
63 case GL_DRAW_FRAMEBUFFER:
64 if (context->fbo_draw_binding == f) return;
65 context->fbo_draw_binding = f;
66 break;
68 case GL_FRAMEBUFFER:
69 if (context->fbo_read_binding == f
70 && context->fbo_draw_binding == f) return;
71 context->fbo_read_binding = f;
72 context->fbo_draw_binding = f;
73 break;
75 default:
76 FIXME("Unhandled target %#x.\n", target);
77 break;
80 gl_info->fbo_ops.glBindFramebuffer(target, f);
81 checkGLcall("glBindFramebuffer()");
84 /* GL locking is done by the caller */
85 static void context_clean_fbo_attachments(const struct wined3d_gl_info *gl_info, GLenum target)
87 unsigned int i;
89 for (i = 0; i < gl_info->limits.buffers; ++i)
91 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
92 checkGLcall("glFramebufferTexture2D()");
94 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
95 checkGLcall("glFramebufferTexture2D()");
97 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
98 checkGLcall("glFramebufferTexture2D()");
101 /* GL locking is done by the caller */
102 static void context_destroy_fbo(struct wined3d_context *context, GLuint *fbo)
104 const struct wined3d_gl_info *gl_info = context->gl_info;
106 context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
107 context_clean_fbo_attachments(gl_info, GL_FRAMEBUFFER);
108 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
110 gl_info->fbo_ops.glDeleteFramebuffers(1, fbo);
111 checkGLcall("glDeleteFramebuffers()");
114 /* GL locking is done by the caller */
115 void context_attach_depth_stencil_fbo(struct wined3d_context *context,
116 GLenum fbo_target, struct wined3d_surface *depth_stencil, BOOL use_render_buffer)
118 const struct wined3d_gl_info *gl_info = context->gl_info;
120 TRACE("Attach depth stencil %p\n", depth_stencil);
122 if (depth_stencil)
124 DWORD format_flags = depth_stencil->resource.format->flags;
126 if (use_render_buffer && depth_stencil->current_renderbuffer)
128 if (format_flags & WINED3DFMT_FLAG_DEPTH)
130 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT,
131 GL_RENDERBUFFER, depth_stencil->current_renderbuffer->id);
132 checkGLcall("glFramebufferRenderbuffer()");
135 if (format_flags & WINED3DFMT_FLAG_STENCIL)
137 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT,
138 GL_RENDERBUFFER, depth_stencil->current_renderbuffer->id);
139 checkGLcall("glFramebufferRenderbuffer()");
142 else
144 surface_prepare_texture(depth_stencil, gl_info, FALSE);
146 if (format_flags & WINED3DFMT_FLAG_DEPTH)
148 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
149 depth_stencil->texture_target, depth_stencil->texture_name,
150 depth_stencil->texture_level);
151 checkGLcall("glFramebufferTexture2D()");
154 if (format_flags & WINED3DFMT_FLAG_STENCIL)
156 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
157 depth_stencil->texture_target, depth_stencil->texture_name,
158 depth_stencil->texture_level);
159 checkGLcall("glFramebufferTexture2D()");
163 if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
165 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
166 checkGLcall("glFramebufferTexture2D()");
169 if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
171 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
172 checkGLcall("glFramebufferTexture2D()");
175 else
177 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
178 checkGLcall("glFramebufferTexture2D()");
180 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
181 checkGLcall("glFramebufferTexture2D()");
185 /* GL locking is done by the caller */
186 static void context_attach_surface_fbo(const struct wined3d_context *context,
187 GLenum fbo_target, DWORD idx, struct wined3d_surface *surface, DWORD location)
189 const struct wined3d_gl_info *gl_info = context->gl_info;
191 TRACE("Attach surface %p to %u\n", surface, idx);
193 if (surface && surface->resource.format->id != WINED3DFMT_NULL)
195 BOOL srgb;
197 switch (location)
199 case SFLAG_INTEXTURE:
200 case SFLAG_INSRGBTEX:
201 srgb = location == SFLAG_INSRGBTEX;
202 surface_prepare_texture(surface, gl_info, srgb);
203 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
204 surface->texture_target, surface_get_texture_name(surface, gl_info, srgb),
205 surface->texture_level);
206 break;
208 default:
209 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
210 break;
212 checkGLcall("glFramebufferTexture2D()");
214 else
216 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
217 checkGLcall("glFramebufferTexture2D()");
221 /* GL locking is done by the caller */
222 void context_check_fbo_status(struct wined3d_context *context, GLenum target)
224 const struct wined3d_gl_info *gl_info = context->gl_info;
225 GLenum status;
227 if (!FIXME_ON(d3d)) return;
229 status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
230 if (status == GL_FRAMEBUFFER_COMPLETE)
232 TRACE("FBO complete\n");
234 else
236 struct wined3d_surface *attachment;
237 unsigned int i;
239 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
241 if (!context->current_fbo)
243 ERR("FBO 0 is incomplete, driver bug?\n");
244 return;
247 FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location),
248 context->current_fbo->location);
250 /* Dump the FBO attachments */
251 for (i = 0; i < gl_info->limits.buffers; ++i)
253 attachment = context->current_fbo->render_targets[i];
254 if (attachment)
256 FIXME("\tColor attachment %d: (%p) %s %ux%u\n",
257 i, attachment, debug_d3dformat(attachment->resource.format->id),
258 attachment->pow2Width, attachment->pow2Height);
261 attachment = context->current_fbo->depth_stencil;
262 if (attachment)
264 FIXME("\tDepth attachment: (%p) %s %ux%u\n",
265 attachment, debug_d3dformat(attachment->resource.format->id),
266 attachment->pow2Width, attachment->pow2Height);
271 static struct fbo_entry *context_create_fbo_entry(struct wined3d_context *context,
272 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
274 const struct wined3d_gl_info *gl_info = context->gl_info;
275 struct fbo_entry *entry;
277 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
278 entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
279 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
280 entry->depth_stencil = depth_stencil;
281 entry->location = location;
282 entry->attached = FALSE;
283 entry->id = 0;
285 return entry;
288 /* GL locking is done by the caller */
289 static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
290 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
291 DWORD location, struct fbo_entry *entry)
293 const struct wined3d_gl_info *gl_info = context->gl_info;
295 context_bind_fbo(context, target, &entry->id);
296 context_clean_fbo_attachments(gl_info, target);
298 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
299 entry->depth_stencil = depth_stencil;
300 entry->location = location;
301 entry->attached = FALSE;
304 /* GL locking is done by the caller */
305 static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
307 if (entry->id)
309 TRACE("Destroy FBO %d\n", entry->id);
310 context_destroy_fbo(context, &entry->id);
312 --context->fbo_entry_count;
313 list_remove(&entry->entry);
314 HeapFree(GetProcessHeap(), 0, entry->render_targets);
315 HeapFree(GetProcessHeap(), 0, entry);
319 /* GL locking is done by the caller */
320 static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
321 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
323 const struct wined3d_gl_info *gl_info = context->gl_info;
324 struct fbo_entry *entry;
326 if (depth_stencil && render_targets && render_targets[0])
328 if (depth_stencil->resource.width < render_targets[0]->resource.width ||
329 depth_stencil->resource.height < render_targets[0]->resource.height)
331 WARN("Depth stencil is smaller than the primary color buffer, disabling\n");
332 depth_stencil = NULL;
336 LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
338 if (!memcmp(entry->render_targets,
339 render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
340 && entry->depth_stencil == depth_stencil && entry->location == location)
342 list_remove(&entry->entry);
343 list_add_head(&context->fbo_list, &entry->entry);
344 return entry;
348 if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
350 entry = context_create_fbo_entry(context, render_targets, depth_stencil, location);
351 list_add_head(&context->fbo_list, &entry->entry);
352 ++context->fbo_entry_count;
354 else
356 entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
357 context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry);
358 list_remove(&entry->entry);
359 list_add_head(&context->fbo_list, &entry->entry);
362 return entry;
365 /* GL locking is done by the caller */
366 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
368 const struct wined3d_gl_info *gl_info = context->gl_info;
369 unsigned int i;
371 context_bind_fbo(context, target, &entry->id);
373 if (entry->attached) return;
375 /* Apply render targets */
376 for (i = 0; i < gl_info->limits.buffers; ++i)
378 context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location);
381 /* Apply depth targets */
382 if (entry->depth_stencil)
383 surface_set_compatible_renderbuffer(entry->depth_stencil, entry->render_targets[0]);
384 context_attach_depth_stencil_fbo(context, target, entry->depth_stencil, TRUE);
386 entry->attached = TRUE;
389 /* GL locking is done by the caller */
390 static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
391 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
393 struct fbo_entry *entry, *entry2;
395 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
397 context_destroy_fbo_entry(context, entry);
400 if (context->rebind_fbo)
402 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
403 context->rebind_fbo = FALSE;
406 if (render_targets)
408 context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
409 context_apply_fbo_entry(context, target, context->current_fbo);
411 else
413 context->current_fbo = NULL;
414 context_bind_fbo(context, target, NULL);
418 /* GL locking is done by the caller */
419 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
420 struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
422 if (location != SFLAG_INDRAWABLE || surface_is_offscreen(render_target))
424 UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets);
425 context->blit_targets[0] = render_target;
426 if (clear_size) memset(&context->blit_targets[1], 0, clear_size);
427 context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location);
429 else
431 context_apply_fbo_state(context, target, NULL, NULL, location);
435 /* Context activation is done by the caller. */
436 void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
438 const struct wined3d_gl_info *gl_info = context->gl_info;
440 if (context->free_occlusion_query_count)
442 query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
444 else
446 if (gl_info->supported[ARB_OCCLUSION_QUERY])
448 ENTER_GL();
449 GL_EXTCALL(glGenQueriesARB(1, &query->id));
450 checkGLcall("glGenQueriesARB");
451 LEAVE_GL();
453 TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
455 else
457 WARN("Occlusion queries not supported, not allocating query id.\n");
458 query->id = 0;
462 query->context = context;
463 list_add_head(&context->occlusion_queries, &query->entry);
466 void context_free_occlusion_query(struct wined3d_occlusion_query *query)
468 struct wined3d_context *context = query->context;
470 list_remove(&query->entry);
471 query->context = NULL;
473 if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
475 UINT new_size = context->free_occlusion_query_size << 1;
476 GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
477 new_size * sizeof(*context->free_occlusion_queries));
479 if (!new_data)
481 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
482 return;
485 context->free_occlusion_query_size = new_size;
486 context->free_occlusion_queries = new_data;
489 context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
492 /* Context activation is done by the caller. */
493 void context_alloc_event_query(struct wined3d_context *context, struct wined3d_event_query *query)
495 const struct wined3d_gl_info *gl_info = context->gl_info;
497 if (context->free_event_query_count)
499 query->object = context->free_event_queries[--context->free_event_query_count];
501 else
503 if (gl_info->supported[ARB_SYNC])
505 /* Using ARB_sync, not much to do here. */
506 query->object.sync = NULL;
507 TRACE("Allocated event query %p in context %p.\n", query->object.sync, context);
509 else if (gl_info->supported[APPLE_FENCE])
511 ENTER_GL();
512 GL_EXTCALL(glGenFencesAPPLE(1, &query->object.id));
513 checkGLcall("glGenFencesAPPLE");
514 LEAVE_GL();
516 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
518 else if(gl_info->supported[NV_FENCE])
520 ENTER_GL();
521 GL_EXTCALL(glGenFencesNV(1, &query->object.id));
522 checkGLcall("glGenFencesNV");
523 LEAVE_GL();
525 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
527 else
529 WARN("Event queries not supported, not allocating query id.\n");
530 query->object.id = 0;
534 query->context = context;
535 list_add_head(&context->event_queries, &query->entry);
538 void context_free_event_query(struct wined3d_event_query *query)
540 struct wined3d_context *context = query->context;
542 list_remove(&query->entry);
543 query->context = NULL;
545 if (context->free_event_query_count >= context->free_event_query_size - 1)
547 UINT new_size = context->free_event_query_size << 1;
548 union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
549 new_size * sizeof(*context->free_event_queries));
551 if (!new_data)
553 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->object.id, context);
554 return;
557 context->free_event_query_size = new_size;
558 context->free_event_queries = new_data;
561 context->free_event_queries[context->free_event_query_count++] = query->object;
564 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
566 static void context_enum_surface_fbo_entries(struct wined3d_device *device,
567 struct wined3d_surface *surface, context_fbo_entry_func_t *callback)
569 UINT i;
571 for (i = 0; i < device->context_count; ++i)
573 struct wined3d_context *context = device->contexts[i];
574 const struct wined3d_gl_info *gl_info = context->gl_info;
575 struct fbo_entry *entry, *entry2;
577 if (context->current_rt == surface) context->current_rt = NULL;
579 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
581 UINT j;
583 if (entry->depth_stencil == surface)
585 callback(context, entry);
586 continue;
589 for (j = 0; j < gl_info->limits.buffers; ++j)
591 if (entry->render_targets[j] == surface)
593 callback(context, entry);
594 break;
601 static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
603 list_remove(&entry->entry);
604 list_add_head(&context->fbo_destroy_list, &entry->entry);
607 void context_resource_released(struct wined3d_device *device,
608 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
610 if (!device->d3d_initialized) return;
612 switch (type)
614 case WINED3DRTYPE_SURFACE:
615 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
616 context_queue_fbo_entry_destruction);
617 break;
619 default:
620 break;
624 static void context_detach_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
626 entry->attached = FALSE;
629 void context_resource_unloaded(struct wined3d_device *device,
630 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
632 switch (type)
634 case WINED3DRTYPE_SURFACE:
635 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
636 context_detach_fbo_entry);
637 break;
639 default:
640 break;
644 void context_surface_update(struct wined3d_context *context, struct wined3d_surface *surface)
646 const struct wined3d_gl_info *gl_info = context->gl_info;
647 struct fbo_entry *entry = context->current_fbo;
648 unsigned int i;
650 if (!entry || context->rebind_fbo) return;
652 for (i = 0; i < gl_info->limits.buffers; ++i)
654 if (surface == entry->render_targets[i])
656 TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
657 context->rebind_fbo = TRUE;
658 return;
662 if (surface == entry->depth_stencil)
664 TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
665 context->rebind_fbo = TRUE;
669 static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
671 int current = GetPixelFormat(dc);
673 if (current == format) return TRUE;
675 if (!current)
677 if (!SetPixelFormat(dc, format, NULL))
679 ERR("Failed to set pixel format %d on device context %p, last error %#x.\n",
680 format, dc, GetLastError());
681 return FALSE;
683 return TRUE;
686 /* By default WGL doesn't allow pixel format adjustments but we need it
687 * here. For this reason there's a Wine specific wglSetPixelFormat()
688 * which allows us to set the pixel format multiple times. Only use it
689 * when really needed. */
690 if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
692 if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format, NULL)))
694 ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
695 format, dc);
696 return FALSE;
698 return TRUE;
701 /* OpenGL doesn't allow pixel format adjustments. Print an error and
702 * continue using the old format. There's a big chance that the old
703 * format works although with a performance hit and perhaps rendering
704 * errors. */
705 ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
706 format, dc, current);
707 return TRUE;
710 static BOOL context_set_gl_context(struct wined3d_context *ctx)
712 struct wined3d_swapchain *swapchain = ctx->swapchain;
714 if (!pwglMakeCurrent(ctx->hdc, ctx->glCtx))
716 WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
717 ctx->glCtx, ctx->hdc, GetLastError());
718 ctx->valid = 0;
719 WARN("Trying fallback to the backup window.\n");
721 if (!swapchain->backup_dc)
723 TRACE("Creating the backup window for swapchain %p.\n", swapchain);
724 swapchain->backup_wnd = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D fake window",
725 WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL);
726 if (!swapchain->backup_wnd)
728 ERR("Failed to create a window.\n");
729 goto fail;
731 swapchain->backup_dc = GetDC(swapchain->backup_wnd);
732 if (!swapchain->backup_dc)
734 ERR("Failed to get a DC.\n");
735 goto fail;
737 if (!context_set_pixel_format(ctx->gl_info, swapchain->backup_dc, ctx->pixel_format))
739 ERR("Failed to set pixel format %d on device context %p.\n",
740 ctx->pixel_format, swapchain->backup_dc);
741 goto fail;
745 if (!pwglMakeCurrent(swapchain->backup_dc, ctx->glCtx))
747 ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
748 swapchain->backup_dc, GetLastError());
749 context_set_current(NULL);
750 return FALSE;
753 return TRUE;
755 fail:
756 if (swapchain->backup_dc)
758 ReleaseDC(swapchain->backup_wnd, swapchain->backup_dc);
759 swapchain->backup_dc = NULL;
761 if (swapchain->backup_wnd)
763 DestroyWindow(swapchain->backup_wnd);
764 swapchain->backup_wnd = NULL;
766 context_set_current(NULL);
767 return FALSE;
770 static void context_restore_gl_context(HDC dc, HGLRC gl_ctx)
772 if (!pwglMakeCurrent(dc, gl_ctx))
774 ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
775 gl_ctx, dc, GetLastError());
776 context_set_current(NULL);
780 static void context_update_window(struct wined3d_context *context)
782 if (context->win_handle == context->swapchain->win_handle)
783 return;
785 TRACE("Updating context %p window from %p to %p.\n",
786 context, context->win_handle, context->swapchain->win_handle);
788 if (context->valid)
790 /* You'd figure ReleaseDC() would fail if the DC doesn't match the
791 * window. However, that's not what actually happens, and there are
792 * user32 tests that confirm ReleaseDC() with the wrong window is
793 * supposed to succeed. So explicitly check that the DC belongs to
794 * the window, since we want to avoid releasing a DC that belongs to
795 * some other window if the original window was already destroyed. */
796 if (WindowFromDC(context->hdc) != context->win_handle)
798 WARN("DC %p does not belong to window %p.\n",
799 context->hdc, context->win_handle);
801 else if (!ReleaseDC(context->win_handle, context->hdc))
803 ERR("Failed to release device context %p, last error %#x.\n",
804 context->hdc, GetLastError());
807 else context->valid = 1;
809 context->win_handle = context->swapchain->win_handle;
811 if (!(context->hdc = GetDC(context->win_handle)))
813 ERR("Failed to get a device context for window %p.\n", context->win_handle);
814 goto err;
817 if (!context_set_pixel_format(context->gl_info, context->hdc, context->pixel_format))
819 ERR("Failed to set pixel format %d on device context %p.\n",
820 context->pixel_format, context->hdc);
821 goto err;
824 context_set_gl_context(context);
826 return;
828 err:
829 context->valid = 0;
832 /* Do not call while under the GL lock. */
833 static void context_destroy_gl_resources(struct wined3d_context *context)
835 const struct wined3d_gl_info *gl_info = context->gl_info;
836 struct wined3d_occlusion_query *occlusion_query;
837 struct wined3d_event_query *event_query;
838 struct fbo_entry *entry, *entry2;
839 HGLRC restore_ctx;
840 HDC restore_dc;
841 unsigned int i;
843 restore_ctx = pwglGetCurrentContext();
844 restore_dc = pwglGetCurrentDC();
846 context_update_window(context);
847 if (context->valid && restore_ctx != context->glCtx)
848 context_set_gl_context(context);
849 else restore_ctx = NULL;
851 ENTER_GL();
853 LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
855 if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
856 GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
857 occlusion_query->context = NULL;
860 LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
862 if (context->valid)
864 if (gl_info->supported[ARB_SYNC])
866 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
868 else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
869 else if (gl_info->supported[NV_FENCE]) GL_EXTCALL(glDeleteFencesNV(1, &event_query->object.id));
871 event_query->context = NULL;
874 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
876 if (!context->valid) entry->id = 0;
877 context_destroy_fbo_entry(context, entry);
880 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
882 if (!context->valid) entry->id = 0;
883 context_destroy_fbo_entry(context, entry);
886 if (context->valid)
888 if (context->dst_fbo)
890 TRACE("Destroy dst FBO %d\n", context->dst_fbo);
891 context_destroy_fbo(context, &context->dst_fbo);
893 if (context->dummy_arbfp_prog)
895 GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
898 if (gl_info->supported[ARB_OCCLUSION_QUERY])
899 GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
901 if (gl_info->supported[ARB_SYNC])
903 for (i = 0; i < context->free_event_query_count; ++i)
905 GL_EXTCALL(glDeleteSync(context->free_event_queries[i].sync));
908 else if (gl_info->supported[APPLE_FENCE])
910 for (i = 0; i < context->free_event_query_count; ++i)
912 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_event_queries[i].id));
915 else if (gl_info->supported[NV_FENCE])
917 for (i = 0; i < context->free_event_query_count; ++i)
919 GL_EXTCALL(glDeleteFencesNV(1, &context->free_event_queries[i].id));
923 checkGLcall("context cleanup");
926 LEAVE_GL();
928 HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
929 HeapFree(GetProcessHeap(), 0, context->free_event_queries);
931 if (restore_ctx)
933 context_restore_gl_context(restore_dc, restore_ctx);
935 else if (pwglGetCurrentContext() && !pwglMakeCurrent(NULL, NULL))
937 ERR("Failed to disable GL context.\n");
940 ReleaseDC(context->win_handle, context->hdc);
942 if (!pwglDeleteContext(context->glCtx))
944 DWORD err = GetLastError();
945 ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
949 DWORD context_get_tls_idx(void)
951 return wined3d_context_tls_idx;
954 void context_set_tls_idx(DWORD idx)
956 wined3d_context_tls_idx = idx;
959 struct wined3d_context *context_get_current(void)
961 return TlsGetValue(wined3d_context_tls_idx);
964 /* Do not call while under the GL lock. */
965 BOOL context_set_current(struct wined3d_context *ctx)
967 struct wined3d_context *old = context_get_current();
969 if (old == ctx)
971 TRACE("Already using D3D context %p.\n", ctx);
972 return TRUE;
975 if (old)
977 if (old->destroyed)
979 TRACE("Switching away from destroyed context %p.\n", old);
980 context_destroy_gl_resources(old);
981 HeapFree(GetProcessHeap(), 0, old);
983 else
985 old->current = 0;
989 if (ctx)
991 if (!ctx->valid)
993 ERR("Trying to make invalid context %p current\n", ctx);
994 return FALSE;
997 TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
998 if (!context_set_gl_context(ctx))
999 return FALSE;
1000 ctx->current = 1;
1002 else if(pwglGetCurrentContext())
1004 TRACE("Clearing current D3D context.\n");
1005 if (!pwglMakeCurrent(NULL, NULL))
1007 DWORD err = GetLastError();
1008 ERR("Failed to clear current GL context, last error %#x.\n", err);
1009 TlsSetValue(wined3d_context_tls_idx, NULL);
1010 return FALSE;
1014 return TlsSetValue(wined3d_context_tls_idx, ctx);
1017 void context_release(struct wined3d_context *context)
1019 TRACE("Releasing context %p, level %u.\n", context, context->level);
1021 if (WARN_ON(d3d))
1023 if (!context->level)
1024 WARN("Context %p is not active.\n", context);
1025 else if (context != context_get_current())
1026 WARN("Context %p is not the current context.\n", context);
1029 if (!--context->level && context->restore_ctx)
1031 TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1032 context_restore_gl_context(context->restore_dc, context->restore_ctx);
1033 context->restore_ctx = NULL;
1034 context->restore_dc = NULL;
1038 static void context_enter(struct wined3d_context *context)
1040 TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1042 if (!context->level++)
1044 const struct wined3d_context *current_context = context_get_current();
1045 HGLRC current_gl = pwglGetCurrentContext();
1047 if (current_gl && (!current_context || current_context->glCtx != current_gl))
1049 TRACE("Another GL context (%p on device context %p) is already current.\n",
1050 current_gl, pwglGetCurrentDC());
1051 context->restore_ctx = current_gl;
1052 context->restore_dc = pwglGetCurrentDC();
1057 static void context_invalidate_state(struct wined3d_context *context,
1058 DWORD state, const struct StateEntry *state_table)
1060 DWORD rep = state_table[state].representative;
1061 DWORD idx;
1062 BYTE shift;
1064 if (isStateDirty(context, rep)) return;
1066 context->dirtyArray[context->numDirtyEntries++] = rep;
1067 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1068 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1069 context->isStateDirty[idx] |= (1 << shift);
1072 /* This function takes care of WineD3D pixel format selection. */
1073 static int WineD3D_ChoosePixelFormat(struct wined3d_device *device, HDC hdc,
1074 const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1075 BOOL auxBuffers, int numSamples, BOOL findCompatible)
1077 int iPixelFormat=0;
1078 unsigned int matchtry;
1079 BYTE redBits, greenBits, blueBits, alphaBits, colorBits;
1080 BYTE depthBits=0, stencilBits=0;
1082 static const struct
1084 BOOL require_aux;
1085 BOOL exact_alpha;
1086 BOOL exact_color;
1088 matches[] =
1090 /* First, try without alpha match buffers. MacOS supports aux buffers only
1091 * on A8R8G8B8, and we prefer better offscreen rendering over an alpha match.
1092 * Then try without aux buffers - this is the most common cause for not
1093 * finding a pixel format. Also some drivers(the open source ones)
1094 * only offer 32 bit ARB pixel formats. First try without an exact alpha
1095 * match, then try without an exact alpha and color match.
1097 { TRUE, TRUE, TRUE },
1098 { TRUE, FALSE, TRUE },
1099 { FALSE, TRUE, TRUE },
1100 { FALSE, FALSE, TRUE },
1101 { TRUE, FALSE, FALSE },
1102 { FALSE, FALSE, FALSE },
1105 int i = 0;
1106 int nCfgs = device->adapter->nCfgs;
1108 TRACE("ColorFormat=%s, DepthStencilFormat=%s, auxBuffers=%d, numSamples=%d, findCompatible=%d\n",
1109 debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1110 auxBuffers, numSamples, findCompatible);
1112 if (!getColorBits(color_format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits))
1114 ERR("Unable to get color bits for format %s (%#x)!\n",
1115 debug_d3dformat(color_format->id), color_format->id);
1116 return 0;
1119 getDepthStencilBits(ds_format, &depthBits, &stencilBits);
1121 for (matchtry = 0; matchtry < (sizeof(matches) / sizeof(*matches)) && !iPixelFormat; ++matchtry)
1123 for (i = 0; i < nCfgs; ++i)
1125 const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1126 BOOL exactDepthMatch = TRUE;
1128 /* For now only accept RGBA formats. Perhaps some day we will
1129 * allow floating point formats for pbuffers. */
1130 if(cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1131 continue;
1133 /* In window mode we need a window drawable format and double buffering. */
1134 if(!(cfg->windowDrawable && cfg->doubleBuffer))
1135 continue;
1137 /* We like to have aux buffers in backbuffer mode */
1138 if(auxBuffers && !cfg->auxBuffers && matches[matchtry].require_aux)
1139 continue;
1141 if(matches[matchtry].exact_color) {
1142 if(cfg->redSize != redBits)
1143 continue;
1144 if(cfg->greenSize != greenBits)
1145 continue;
1146 if(cfg->blueSize != blueBits)
1147 continue;
1148 } else {
1149 if(cfg->redSize < redBits)
1150 continue;
1151 if(cfg->greenSize < greenBits)
1152 continue;
1153 if(cfg->blueSize < blueBits)
1154 continue;
1156 if(matches[matchtry].exact_alpha) {
1157 if(cfg->alphaSize != alphaBits)
1158 continue;
1159 } else {
1160 if(cfg->alphaSize < alphaBits)
1161 continue;
1164 /* We try to locate a format which matches our requirements exactly. In case of
1165 * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1166 if(cfg->depthSize < depthBits)
1167 continue;
1168 else if(cfg->depthSize > depthBits)
1169 exactDepthMatch = FALSE;
1171 /* In all cases make sure the number of stencil bits matches our requirements
1172 * even when we don't need stencil because it could affect performance EXCEPT
1173 * on cards which don't offer depth formats without stencil like the i915 drivers
1174 * on Linux. */
1175 if (stencilBits != cfg->stencilSize
1176 && !(device->adapter->brokenStencil && stencilBits <= cfg->stencilSize))
1177 continue;
1179 /* Check multisampling support */
1180 if(cfg->numSamples != numSamples)
1181 continue;
1183 /* When we have passed all the checks then we have found a format which matches our
1184 * requirements. Note that we only check for a limit number of capabilities right now,
1185 * so there can easily be a dozen of pixel formats which appear to be the 'same' but
1186 * can still differ in things like multisampling, stereo, SRGB and other flags.
1189 /* Exit the loop as we have found a format :) */
1190 if(exactDepthMatch) {
1191 iPixelFormat = cfg->iPixelFormat;
1192 break;
1193 } else if(!iPixelFormat) {
1194 /* In the end we might end up with a format which doesn't exactly match our depth
1195 * requirements. Accept the first format we found because formats with higher iPixelFormat
1196 * values tend to have more extended capabilities (e.g. multisampling) which we don't need. */
1197 iPixelFormat = cfg->iPixelFormat;
1202 /* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
1203 if(!iPixelFormat && !findCompatible) {
1204 ERR("Can't find a suitable iPixelFormat\n");
1205 return FALSE;
1206 } else if(!iPixelFormat) {
1207 PIXELFORMATDESCRIPTOR pfd;
1209 TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
1210 /* PixelFormat selection */
1211 ZeroMemory(&pfd, sizeof(pfd));
1212 pfd.nSize = sizeof(pfd);
1213 pfd.nVersion = 1;
1214 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1215 pfd.iPixelType = PFD_TYPE_RGBA;
1216 pfd.cAlphaBits = alphaBits;
1217 pfd.cColorBits = colorBits;
1218 pfd.cDepthBits = depthBits;
1219 pfd.cStencilBits = stencilBits;
1220 pfd.iLayerType = PFD_MAIN_PLANE;
1222 iPixelFormat = ChoosePixelFormat(hdc, &pfd);
1223 if(!iPixelFormat) {
1224 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
1225 ERR("Can't find a suitable iPixelFormat\n");
1226 return FALSE;
1230 TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
1231 iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1232 return iPixelFormat;
1235 static inline DWORD generate_rt_mask(GLenum buffer)
1237 /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
1238 return buffer ? (1 << 31) | buffer : 0;
1241 static inline DWORD generate_rt_mask_from_surface(struct wined3d_surface *target)
1243 return (1 << 31) | surface_get_gl_buffer(target);
1246 /* Do not call while under the GL lock. */
1247 struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
1248 struct wined3d_surface *target, const struct wined3d_format *ds_format)
1250 struct wined3d_device *device = swapchain->device;
1251 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1252 const struct wined3d_format *color_format;
1253 struct wined3d_context *ret;
1254 PIXELFORMATDESCRIPTOR pfd;
1255 BOOL auxBuffers = FALSE;
1256 int numSamples = 0;
1257 int pixel_format;
1258 unsigned int s;
1259 int swap_interval;
1260 DWORD state;
1261 HGLRC ctx;
1262 HDC hdc;
1264 TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1266 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1267 if (!ret)
1269 ERR("Failed to allocate context memory.\n");
1270 return NULL;
1273 if (!(hdc = GetDC(swapchain->win_handle)))
1275 ERR("Failed to retrieve a device context.\n");
1276 goto out;
1279 color_format = target->resource.format;
1281 /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
1282 * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
1283 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
1285 auxBuffers = TRUE;
1287 if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
1288 color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM);
1289 else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
1290 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1293 /* DirectDraw supports 8bit paletted render targets and these are used by
1294 * old games like StarCraft and C&C. Most modern hardware doesn't support
1295 * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
1296 * conversion (ab)uses the alpha component for storing the palette index.
1297 * For this reason we require a format with 8bit alpha, so request
1298 * A8R8G8B8. */
1299 if (color_format->id == WINED3DFMT_P8_UINT)
1300 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1302 /* D3D only allows multisampling when SwapEffect is set to WINED3DSWAPEFFECT_DISCARD. */
1303 if (swapchain->presentParms.MultiSampleType && (swapchain->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD))
1305 if (!gl_info->supported[ARB_MULTISAMPLE])
1306 WARN("The application is requesting multisampling without support.\n");
1307 else
1309 TRACE("Requesting multisample type %#x.\n", swapchain->presentParms.MultiSampleType);
1310 numSamples = swapchain->presentParms.MultiSampleType;
1314 /* Try to find a pixel format which matches our requirements. */
1315 pixel_format = WineD3D_ChoosePixelFormat(device, hdc, color_format, ds_format,
1316 auxBuffers, numSamples, FALSE /* findCompatible */);
1318 /* Try to locate a compatible format if we weren't able to find anything. */
1319 if (!pixel_format)
1321 TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
1322 pixel_format = WineD3D_ChoosePixelFormat(device, hdc, color_format, ds_format,
1323 auxBuffers, 0 /* numSamples */, TRUE /* findCompatible */);
1326 /* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
1327 if (!pixel_format)
1329 ERR("Can't find a suitable pixel format.\n");
1330 goto out;
1333 DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd);
1334 if (!context_set_pixel_format(gl_info, hdc, pixel_format))
1336 ERR("Failed to set pixel format %d on device context %p.\n", pixel_format, hdc);
1337 goto out;
1340 ctx = pwglCreateContext(hdc);
1341 if (device->context_count)
1343 if (!pwglShareLists(device->contexts[0]->glCtx, ctx))
1345 DWORD err = GetLastError();
1346 ERR("wglShareLists(%p, %p) failed, last error %#x.\n",
1347 device->contexts[0]->glCtx, ctx, err);
1351 if(!ctx) {
1352 ERR("Failed to create a WGL context\n");
1353 goto out;
1356 if (!device_context_add(device, ret))
1358 ERR("Failed to add the newly created context to the context list\n");
1359 if (!pwglDeleteContext(ctx))
1361 DWORD err = GetLastError();
1362 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, err);
1364 goto out;
1367 ret->gl_info = gl_info;
1369 /* Mark all states dirty to force a proper initialization of the states
1370 * on the first use of the context. */
1371 for (state = 0; state <= STATE_HIGHEST; ++state)
1373 if (device->StateTable[state].representative)
1374 context_invalidate_state(ret, state, device->StateTable);
1377 ret->swapchain = swapchain;
1378 ret->current_rt = target;
1379 ret->tid = GetCurrentThreadId();
1381 ret->render_offscreen = surface_is_offscreen(target);
1382 ret->draw_buffers_mask = generate_rt_mask(GL_BACK);
1383 ret->valid = 1;
1385 ret->glCtx = ctx;
1386 ret->win_handle = swapchain->win_handle;
1387 ret->hdc = hdc;
1388 ret->pixel_format = pixel_format;
1390 if (device->shader_backend->shader_dirtifyable_constants())
1392 /* Create the dirty constants array and initialize them to dirty */
1393 ret->vshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1394 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1395 ret->pshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1396 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1397 memset(ret->vshader_const_dirty, 1,
1398 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1399 memset(ret->pshader_const_dirty, 1,
1400 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1403 ret->blit_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1404 gl_info->limits.buffers * sizeof(*ret->blit_targets));
1405 if (!ret->blit_targets) goto out;
1407 ret->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1408 gl_info->limits.buffers * sizeof(*ret->draw_buffers));
1409 if (!ret->draw_buffers) goto out;
1411 ret->free_occlusion_query_size = 4;
1412 ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
1413 ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
1414 if (!ret->free_occlusion_queries) goto out;
1416 list_init(&ret->occlusion_queries);
1418 ret->free_event_query_size = 4;
1419 ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
1420 ret->free_event_query_size * sizeof(*ret->free_event_queries));
1421 if (!ret->free_event_queries) goto out;
1423 list_init(&ret->event_queries);
1425 TRACE("Successfully created new context %p\n", ret);
1427 list_init(&ret->fbo_list);
1428 list_init(&ret->fbo_destroy_list);
1430 context_enter(ret);
1432 /* Set up the context defaults */
1433 if (!context_set_current(ret))
1435 ERR("Cannot activate context to set up defaults\n");
1436 context_release(ret);
1437 goto out;
1440 switch (swapchain->presentParms.PresentationInterval)
1442 case WINED3DPRESENT_INTERVAL_IMMEDIATE:
1443 swap_interval = 0;
1444 break;
1445 case WINED3DPRESENT_INTERVAL_DEFAULT:
1446 case WINED3DPRESENT_INTERVAL_ONE:
1447 swap_interval = 1;
1448 break;
1449 case WINED3DPRESENT_INTERVAL_TWO:
1450 swap_interval = 2;
1451 break;
1452 case WINED3DPRESENT_INTERVAL_THREE:
1453 swap_interval = 3;
1454 break;
1455 case WINED3DPRESENT_INTERVAL_FOUR:
1456 swap_interval = 4;
1457 break;
1458 default:
1459 FIXME("Unknown presentation interval %08x\n", swapchain->presentParms.PresentationInterval);
1460 swap_interval = 1;
1463 if (gl_info->supported[WGL_EXT_SWAP_CONTROL])
1465 if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
1466 ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
1467 swap_interval, ret, GetLastError());
1470 ENTER_GL();
1472 glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
1474 TRACE("Setting up the screen\n");
1475 /* Clear the screen */
1476 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
1477 checkGLcall("glClearColor");
1478 glClearIndex(0);
1479 glClearDepth(1);
1480 glClearStencil(0xffff);
1482 checkGLcall("glClear");
1484 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1485 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1487 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1488 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1490 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1491 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1493 glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
1494 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
1495 glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);
1496 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
1498 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1500 /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
1501 * and textures in DIB sections(due to the memory protection).
1503 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1504 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1506 if (gl_info->supported[ARB_VERTEX_BLEND])
1508 /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one
1509 * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless
1510 * GL_VERTEX_BLEND_ARB isn't enabled too
1512 glEnable(GL_WEIGHT_SUM_UNITY_ARB);
1513 checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
1515 if (gl_info->supported[NV_TEXTURE_SHADER2])
1517 /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
1518 * the previous texture where to source the offset from is always unit - 1.
1520 for (s = 1; s < gl_info->limits.textures; ++s)
1522 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
1523 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
1524 checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
1527 if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
1529 /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
1530 * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
1531 * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
1532 * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
1533 * is ever assigned.
1535 * So make sure a program is assigned to each context. The first real ARBFP use will set a different
1536 * program and the dummy program is destroyed when the context is destroyed.
1538 const char *dummy_program =
1539 "!!ARBfp1.0\n"
1540 "MOV result.color, fragment.color.primary;\n"
1541 "END\n";
1542 GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
1543 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
1544 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
1547 for (s = 0; s < gl_info->limits.point_sprite_units; ++s)
1549 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
1550 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
1551 checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
1554 if (gl_info->supported[ARB_PROVOKING_VERTEX])
1556 GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
1558 else if (gl_info->supported[EXT_PROVOKING_VERTEX])
1560 GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
1562 device->frag_pipe->enable_extension(TRUE);
1564 LEAVE_GL();
1566 TRACE("Created context %p.\n", ret);
1568 return ret;
1570 out:
1571 HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
1572 HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
1573 HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
1574 HeapFree(GetProcessHeap(), 0, ret->blit_targets);
1575 HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
1576 HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
1577 HeapFree(GetProcessHeap(), 0, ret);
1578 return NULL;
1581 /* Do not call while under the GL lock. */
1582 void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
1584 BOOL destroy;
1586 TRACE("Destroying ctx %p\n", context);
1588 if (context->tid == GetCurrentThreadId() || !context->current)
1590 context_destroy_gl_resources(context);
1591 TlsSetValue(wined3d_context_tls_idx, NULL);
1592 destroy = TRUE;
1594 else
1596 context->destroyed = 1;
1597 destroy = FALSE;
1600 HeapFree(GetProcessHeap(), 0, context->draw_buffers);
1601 HeapFree(GetProcessHeap(), 0, context->blit_targets);
1602 HeapFree(GetProcessHeap(), 0, context->vshader_const_dirty);
1603 HeapFree(GetProcessHeap(), 0, context->pshader_const_dirty);
1604 device_context_remove(device, context);
1605 if (destroy) HeapFree(GetProcessHeap(), 0, context);
1608 /* GL locking is done by the caller */
1609 static inline void set_blit_dimension(UINT width, UINT height) {
1610 glMatrixMode(GL_PROJECTION);
1611 checkGLcall("glMatrixMode(GL_PROJECTION)");
1612 glLoadIdentity();
1613 checkGLcall("glLoadIdentity()");
1614 glOrtho(0, width, 0, height, 0.0, -1.0);
1615 checkGLcall("glOrtho");
1616 glViewport(0, 0, width, height);
1617 checkGLcall("glViewport");
1620 /*****************************************************************************
1621 * SetupForBlit
1623 * Sets up a context for DirectDraw blitting.
1624 * All texture units are disabled, texture unit 0 is set as current unit
1625 * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
1626 * color writing enabled for all channels
1627 * register combiners disabled, shaders disabled
1628 * world matrix is set to identity, texture matrix 0 too
1629 * projection matrix is setup for drawing screen coordinates
1631 * Params:
1632 * This: Device to activate the context for
1633 * context: Context to setup
1635 *****************************************************************************/
1636 /* Context activation is done by the caller. */
1637 static void SetupForBlit(struct wined3d_device *device, struct wined3d_context *context)
1639 int i;
1640 const struct StateEntry *StateTable = device->StateTable;
1641 const struct wined3d_gl_info *gl_info = context->gl_info;
1642 UINT width = context->current_rt->resource.width;
1643 UINT height = context->current_rt->resource.height;
1644 DWORD sampler;
1646 TRACE("Setting up context %p for blitting\n", context);
1647 if(context->last_was_blit) {
1648 if(context->blit_w != width || context->blit_h != height) {
1649 ENTER_GL();
1650 set_blit_dimension(width, height);
1651 LEAVE_GL();
1652 context->blit_w = width; context->blit_h = height;
1653 /* No need to dirtify here, the states are still dirtified because they weren't
1654 * applied since the last SetupForBlit call. Otherwise last_was_blit would not
1655 * be set
1658 TRACE("Context is already set up for blitting, nothing to do\n");
1659 return;
1661 context->last_was_blit = TRUE;
1663 /* TODO: Use a display list */
1665 /* Disable shaders */
1666 ENTER_GL();
1667 device->shader_backend->shader_select(context, FALSE, FALSE);
1668 LEAVE_GL();
1670 context_invalidate_state(context, STATE_VSHADER, StateTable);
1671 context_invalidate_state(context, STATE_PIXELSHADER, StateTable);
1673 /* Call ENTER_GL() once for all gl calls below. In theory we should not call
1674 * helper functions in between gl calls. This function is full of context_invalidate_state
1675 * which can safely be called from here, we only lock once instead locking/unlocking
1676 * after each GL call.
1678 ENTER_GL();
1680 /* Disable all textures. The caller can then bind a texture it wants to blit
1681 * from
1683 * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
1684 * function texture unit. No need to care for higher samplers
1686 for (i = gl_info->limits.textures - 1; i > 0 ; --i)
1688 sampler = device->rev_tex_unit_map[i];
1689 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1690 checkGLcall("glActiveTextureARB");
1692 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1694 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1695 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1697 glDisable(GL_TEXTURE_3D);
1698 checkGLcall("glDisable GL_TEXTURE_3D");
1699 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1701 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1702 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1704 glDisable(GL_TEXTURE_2D);
1705 checkGLcall("glDisable GL_TEXTURE_2D");
1707 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1708 checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
1710 if (sampler != WINED3D_UNMAPPED_STAGE)
1712 if (sampler < MAX_TEXTURES)
1713 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP), StateTable);
1714 context_invalidate_state(context, STATE_SAMPLER(sampler), StateTable);
1717 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1718 checkGLcall("glActiveTextureARB");
1720 sampler = device->rev_tex_unit_map[0];
1722 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1724 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1725 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1727 glDisable(GL_TEXTURE_3D);
1728 checkGLcall("glDisable GL_TEXTURE_3D");
1729 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1731 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1732 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1734 glDisable(GL_TEXTURE_2D);
1735 checkGLcall("glDisable GL_TEXTURE_2D");
1737 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1739 glMatrixMode(GL_TEXTURE);
1740 checkGLcall("glMatrixMode(GL_TEXTURE)");
1741 glLoadIdentity();
1742 checkGLcall("glLoadIdentity()");
1744 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1746 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1747 GL_TEXTURE_LOD_BIAS_EXT,
1748 0.0f);
1749 checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
1752 if (sampler != WINED3D_UNMAPPED_STAGE)
1754 if (sampler < MAX_TEXTURES)
1756 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + sampler), StateTable);
1757 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP), StateTable);
1759 context_invalidate_state(context, STATE_SAMPLER(sampler), StateTable);
1762 /* Other misc states */
1763 glDisable(GL_ALPHA_TEST);
1764 checkGLcall("glDisable(GL_ALPHA_TEST)");
1765 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHATESTENABLE), StateTable);
1766 glDisable(GL_LIGHTING);
1767 checkGLcall("glDisable GL_LIGHTING");
1768 context_invalidate_state(context, STATE_RENDER(WINED3DRS_LIGHTING), StateTable);
1769 glDisable(GL_DEPTH_TEST);
1770 checkGLcall("glDisable GL_DEPTH_TEST");
1771 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ZENABLE), StateTable);
1772 glDisableWINE(GL_FOG);
1773 checkGLcall("glDisable GL_FOG");
1774 context_invalidate_state(context, STATE_RENDER(WINED3DRS_FOGENABLE), StateTable);
1775 glDisable(GL_BLEND);
1776 checkGLcall("glDisable GL_BLEND");
1777 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
1778 glDisable(GL_CULL_FACE);
1779 checkGLcall("glDisable GL_CULL_FACE");
1780 context_invalidate_state(context, STATE_RENDER(WINED3DRS_CULLMODE), StateTable);
1781 glDisable(GL_STENCIL_TEST);
1782 checkGLcall("glDisable GL_STENCIL_TEST");
1783 context_invalidate_state(context, STATE_RENDER(WINED3DRS_STENCILENABLE), StateTable);
1784 glDisable(GL_SCISSOR_TEST);
1785 checkGLcall("glDisable GL_SCISSOR_TEST");
1786 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), StateTable);
1787 if (gl_info->supported[ARB_POINT_SPRITE])
1789 glDisable(GL_POINT_SPRITE_ARB);
1790 checkGLcall("glDisable GL_POINT_SPRITE_ARB");
1791 context_invalidate_state(context, STATE_RENDER(WINED3DRS_POINTSPRITEENABLE), StateTable);
1793 glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
1794 checkGLcall("glColorMask");
1795 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE), StateTable);
1796 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1), StateTable);
1797 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2), StateTable);
1798 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3), StateTable);
1799 if (gl_info->supported[EXT_SECONDARY_COLOR])
1801 glDisable(GL_COLOR_SUM_EXT);
1802 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SPECULARENABLE), StateTable);
1803 checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
1806 /* Setup transforms */
1807 glMatrixMode(GL_MODELVIEW);
1808 checkGLcall("glMatrixMode(GL_MODELVIEW)");
1809 glLoadIdentity();
1810 checkGLcall("glLoadIdentity()");
1811 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), StateTable);
1813 context->last_was_rhw = TRUE;
1814 context_invalidate_state(context, STATE_VDECL, StateTable); /* because of last_was_rhw = TRUE */
1816 glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
1817 glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
1818 glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
1819 glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
1820 glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
1821 glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
1822 context_invalidate_state(context, STATE_RENDER(WINED3DRS_CLIPPING), StateTable);
1824 set_blit_dimension(width, height);
1825 device->frag_pipe->enable_extension(FALSE);
1827 LEAVE_GL();
1829 context->blit_w = width; context->blit_h = height;
1830 context_invalidate_state(context, STATE_VIEWPORT, StateTable);
1831 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
1834 /* Do not call while under the GL lock. */
1835 static struct wined3d_context *FindContext(const struct wined3d_device *device, const struct wined3d_surface *target)
1837 struct wined3d_context *current_context = context_get_current();
1838 struct wined3d_context *context;
1840 if (current_context && current_context->destroyed) current_context = NULL;
1842 if (!target)
1844 if (current_context
1845 && current_context->current_rt
1846 && current_context->swapchain->device == device)
1848 target = current_context->current_rt;
1850 else
1852 struct wined3d_swapchain *swapchain = device->swapchains[0];
1853 if (swapchain->back_buffers) target = swapchain->back_buffers[0];
1854 else target = swapchain->front_buffer;
1858 if (current_context && current_context->current_rt == target)
1860 context_update_window(current_context);
1861 return current_context;
1864 if (target->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1866 TRACE("Rendering onscreen\n");
1868 context = swapchain_get_context(target->container.u.swapchain);
1870 else
1872 TRACE("Rendering offscreen\n");
1874 /* Stay with the current context if possible. Otherwise use the
1875 * context for the primary swapchain. */
1876 if (current_context && current_context->swapchain->device == device)
1877 context = current_context;
1878 else
1879 context = swapchain_get_context(device->swapchains[0]);
1882 context_update_window(context);
1884 return context;
1887 static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
1889 return rt_mask & (1 << 31);
1892 static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
1894 return rt_mask & ~(1 << 31);
1897 /* Context activation and GL locking are done by the caller. */
1898 static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
1900 if (!rt_mask)
1902 glDrawBuffer(GL_NONE);
1903 checkGLcall("glDrawBuffer()");
1905 else if (is_rt_mask_onscreen(rt_mask))
1907 glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
1908 checkGLcall("glDrawBuffer()");
1910 else
1912 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
1914 const struct wined3d_gl_info *gl_info = context->gl_info;
1915 unsigned int i = 0;
1917 while (rt_mask)
1919 if (rt_mask & 1)
1920 context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
1921 else
1922 context->draw_buffers[i] = GL_NONE;
1924 rt_mask >>= 1;
1925 ++i;
1928 if (gl_info->supported[ARB_DRAW_BUFFERS])
1930 GL_EXTCALL(glDrawBuffersARB(i, context->draw_buffers));
1931 checkGLcall("glDrawBuffers()");
1933 else
1935 glDrawBuffer(context->draw_buffers[0]);
1936 checkGLcall("glDrawBuffer()");
1939 else
1941 ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
1946 /* GL locking is done by the caller. */
1947 void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
1949 glDrawBuffer(buffer);
1950 checkGLcall("glDrawBuffer()");
1951 context->draw_buffers_mask = generate_rt_mask(buffer);
1954 static inline void context_set_render_offscreen(struct wined3d_context *context, const struct StateEntry *StateTable,
1955 BOOL offscreen)
1957 if (context->render_offscreen == offscreen) return;
1959 context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN, StateTable);
1960 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
1961 context_invalidate_state(context, STATE_VIEWPORT, StateTable);
1962 context_invalidate_state(context, STATE_SCISSORRECT, StateTable);
1963 context_invalidate_state(context, STATE_FRONTFACE, StateTable);
1964 context->render_offscreen = offscreen;
1967 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
1968 const struct wined3d_format *required)
1970 BYTE existing_depth, existing_stencil, required_depth, required_stencil;
1972 if (existing == required) return TRUE;
1973 if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
1975 getDepthStencilBits(existing, &existing_depth, &existing_stencil);
1976 getDepthStencilBits(required, &required_depth, &required_stencil);
1978 if(existing_depth < required_depth) return FALSE;
1979 /* If stencil bits are used the exact amount is required - otherwise wrapping
1980 * won't work correctly */
1981 if(required_stencil && required_stencil != existing_stencil) return FALSE;
1982 return TRUE;
1985 /* The caller provides a context */
1986 static void context_validate_onscreen_formats(struct wined3d_device *device,
1987 struct wined3d_context *context, struct wined3d_surface *depth_stencil)
1989 /* Onscreen surfaces are always in a swapchain */
1990 struct wined3d_swapchain *swapchain = context->current_rt->container.u.swapchain;
1992 if (context->render_offscreen || !depth_stencil) return;
1993 if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format)) return;
1995 /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
1996 * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
1997 * format. */
1998 WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2000 /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2001 surface_load_location(context->current_rt, SFLAG_INTEXTURE, NULL);
2002 swapchain->render_to_fbo = TRUE;
2003 context_set_render_offscreen(context, device->StateTable, TRUE);
2006 static DWORD generate_rt_mask_no_fbo(struct wined3d_device *device, struct wined3d_surface *rt)
2008 if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
2009 return 0;
2010 else if (rt->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2011 return generate_rt_mask_from_surface(rt);
2012 else
2013 return generate_rt_mask(device->offscreenBuffer);
2016 /* Context activation is done by the caller. */
2017 void context_apply_blit_state(struct wined3d_context *context, struct wined3d_device *device)
2019 DWORD rt_mask;
2021 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2023 context_validate_onscreen_formats(device, context, NULL);
2025 if (context->render_offscreen)
2027 surface_internal_preload(context->current_rt, SRGB_RGB);
2029 ENTER_GL();
2030 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, context->current_rt, NULL, SFLAG_INTEXTURE);
2031 LEAVE_GL();
2032 if (context->current_rt && context->current_rt->resource.format->id != WINED3DFMT_NULL)
2033 rt_mask = 1;
2034 else
2035 rt_mask = 0;
2037 else
2039 ENTER_GL();
2040 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
2041 LEAVE_GL();
2042 rt_mask = generate_rt_mask_from_surface(context->current_rt);
2045 else
2047 rt_mask = generate_rt_mask_no_fbo(device, context->current_rt);
2050 ENTER_GL();
2051 if (rt_mask != context->draw_buffers_mask)
2053 context_apply_draw_buffers(context, rt_mask);
2054 context->draw_buffers_mask = rt_mask;
2057 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2059 context_check_fbo_status(context, GL_FRAMEBUFFER);
2061 LEAVE_GL();
2063 SetupForBlit(device, context);
2066 static BOOL context_validate_rt_config(UINT rt_count,
2067 struct wined3d_surface **rts, struct wined3d_surface *ds)
2069 unsigned int i;
2071 if (ds) return TRUE;
2073 for (i = 0; i < rt_count; ++i)
2075 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2076 return TRUE;
2079 WARN("Invalid render target config, need at least one attachment.\n");
2080 return FALSE;
2083 /* Context activation is done by the caller. */
2084 BOOL context_apply_clear_state(struct wined3d_context *context, struct wined3d_device *device,
2085 UINT rt_count, struct wined3d_surface **rts, struct wined3d_surface *depth_stencil)
2087 const struct StateEntry *state_table = device->StateTable;
2088 DWORD rt_mask = 0;
2089 UINT i;
2091 if (!context_validate_rt_config(rt_count, rts, depth_stencil))
2092 return FALSE;
2095 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2097 context_validate_onscreen_formats(device, context, depth_stencil);
2099 ENTER_GL();
2101 if (!rt_count || surface_is_offscreen(rts[0]))
2103 for (i = 0; i < rt_count; ++i)
2105 context->blit_targets[i] = rts[i];
2106 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2107 rt_mask |= (1 << i);
2109 while (i < context->gl_info->limits.buffers)
2111 context->blit_targets[i] = NULL;
2112 ++i;
2114 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE);
2115 glReadBuffer(GL_NONE);
2116 checkGLcall("glReadBuffer");
2118 else
2120 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2121 rt_mask = generate_rt_mask_from_surface(rts[0]);
2124 LEAVE_GL();
2126 else
2128 rt_mask = generate_rt_mask_no_fbo(device, rts[0]);
2131 ENTER_GL();
2132 if (rt_mask != context->draw_buffers_mask)
2134 context_apply_draw_buffers(context, rt_mask);
2135 context->draw_buffers_mask = rt_mask;
2138 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2140 context_check_fbo_status(context, GL_FRAMEBUFFER);
2143 if (context->last_was_blit)
2145 device->frag_pipe->enable_extension(TRUE);
2146 context->last_was_blit = FALSE;
2149 /* Blending and clearing should be orthogonal, but tests on the nvidia
2150 * driver show that disabling blending when clearing improves the clearing
2151 * performance incredibly. */
2152 glDisable(GL_BLEND);
2153 glEnable(GL_SCISSOR_TEST);
2154 checkGLcall("glEnable GL_SCISSOR_TEST");
2155 LEAVE_GL();
2157 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_table);
2158 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), state_table);
2159 context_invalidate_state(context, STATE_SCISSORRECT, state_table);
2161 return TRUE;
2164 /* Context activation is done by the caller. */
2165 BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
2167 const struct StateEntry *state_table = device->StateTable;
2168 const struct wined3d_fb_state *fb = &device->fb;
2169 unsigned int i;
2170 DWORD rt_mask;
2172 if (!context_validate_rt_config(context->gl_info->limits.buffers,
2173 fb->render_targets, fb->depth_stencil))
2174 return FALSE;
2176 /* Preload resources before FBO setup. Texture preload in particular may
2177 * result in changes to the current FBO, due to using e.g. FBO blits for
2178 * updating a resource location. */
2179 device_update_tex_unit_map(device);
2180 device_preload_textures(device);
2181 if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC))
2182 device_update_stream_info(device, context->gl_info);
2184 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2186 context_validate_onscreen_formats(device, context, fb->depth_stencil);
2188 if (!context->render_offscreen)
2190 ENTER_GL();
2191 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2192 LEAVE_GL();
2193 rt_mask = generate_rt_mask_from_surface(fb->render_targets[0]);
2195 else
2197 const struct wined3d_shader *ps = device->stateBlock->state.pixel_shader;
2198 DWORD rt_mask_bits;
2199 struct wined3d_surface **rts = fb->render_targets;
2201 ENTER_GL();
2202 context_apply_fbo_state(context, GL_FRAMEBUFFER, fb->render_targets, fb->depth_stencil, SFLAG_INTEXTURE);
2203 glReadBuffer(GL_NONE);
2204 checkGLcall("glReadBuffer");
2205 LEAVE_GL();
2206 rt_mask = ps ? ps->reg_maps.rt_mask : 1;
2207 rt_mask &= device->valid_rt_mask;
2208 rt_mask_bits = rt_mask;
2209 i = 0;
2210 while (rt_mask_bits)
2212 rt_mask_bits &= ~(1 << i);
2213 if (!rts[i] || rts[i]->resource.format->id == WINED3DFMT_NULL)
2214 rt_mask &= ~(1 << i);
2216 i++;
2220 else
2222 rt_mask = generate_rt_mask_no_fbo(device, fb->render_targets[0]);
2225 ENTER_GL();
2226 if (context->draw_buffers_mask != rt_mask)
2228 context_apply_draw_buffers(context, rt_mask);
2229 context->draw_buffers_mask = rt_mask;
2232 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2234 context_check_fbo_status(context, GL_FRAMEBUFFER);
2237 if (context->last_was_blit)
2239 device->frag_pipe->enable_extension(TRUE);
2242 for (i = 0; i < context->numDirtyEntries; ++i)
2244 DWORD rep = context->dirtyArray[i];
2245 DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
2246 BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
2247 context->isStateDirty[idx] &= ~(1 << shift);
2248 state_table[rep].apply(rep, device->stateBlock, context);
2250 LEAVE_GL();
2251 context->numDirtyEntries = 0; /* This makes the whole list clean */
2252 context->last_was_blit = FALSE;
2254 return TRUE;
2257 static void context_setup_target(struct wined3d_device *device,
2258 struct wined3d_context *context, struct wined3d_surface *target)
2260 BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
2261 const struct StateEntry *StateTable = device->StateTable;
2263 if (!target) return;
2264 render_offscreen = surface_is_offscreen(target);
2265 if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
2267 /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
2268 * the alpha blend state changes with different render target formats. */
2269 if (!context->current_rt)
2271 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
2273 else
2275 const struct wined3d_format *old = context->current_rt->resource.format;
2276 const struct wined3d_format *new = target->resource.format;
2278 if (old->id != new->id)
2280 /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
2281 if ((old->alpha_mask && !new->alpha_mask) || (!old->alpha_mask && new->alpha_mask)
2282 || !(new->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
2283 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
2285 /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
2286 if ((old->flags & WINED3DFMT_FLAG_SRGB_WRITE) != (new->flags & WINED3DFMT_FLAG_SRGB_WRITE))
2287 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SRGBWRITEENABLE), StateTable);
2290 /* When switching away from an offscreen render target, and we're not
2291 * using FBOs, we have to read the drawable into the texture. This is
2292 * done via PreLoad (and SFLAG_INDRAWABLE set on the surface). There
2293 * are some things that need care though. PreLoad needs a GL context,
2294 * and FindContext is called before the context is activated. It also
2295 * has to be called with the old rendertarget active, otherwise a
2296 * wrong drawable is read. */
2297 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2298 && old_render_offscreen && context->current_rt != target)
2300 /* Read the back buffer of the old drawable into the destination texture. */
2301 if (context->current_rt->texture_name_srgb)
2302 surface_internal_preload(context->current_rt, SRGB_SRGB);
2303 surface_internal_preload(context->current_rt, SRGB_RGB);
2304 surface_modify_location(context->current_rt, SFLAG_INDRAWABLE, FALSE);
2308 context->current_rt = target;
2309 context_set_render_offscreen(context, StateTable, render_offscreen);
2312 /* Do not call while under the GL lock. */
2313 struct wined3d_context *context_acquire(struct wined3d_device *device, struct wined3d_surface *target)
2315 struct wined3d_context *current_context = context_get_current();
2316 struct wined3d_context *context;
2318 TRACE("device %p, target %p.\n", device, target);
2320 context = FindContext(device, target);
2321 context_setup_target(device, context, target);
2322 context_enter(context);
2323 if (!context->valid) return context;
2325 if (context != current_context)
2327 if (!context_set_current(context))
2329 ERR("Failed to activate the new context.\n");
2331 else
2333 ENTER_GL();
2334 device->frag_pipe->enable_extension(!context->last_was_blit);
2335 LEAVE_GL();
2338 if (context->vshader_const_dirty)
2340 memset(context->vshader_const_dirty, 1,
2341 sizeof(*context->vshader_const_dirty) * device->d3d_vshader_constantF);
2342 device->highest_dirty_vs_const = device->d3d_vshader_constantF;
2344 if (context->pshader_const_dirty)
2346 memset(context->pshader_const_dirty, 1,
2347 sizeof(*context->pshader_const_dirty) * device->d3d_pshader_constantF);
2348 device->highest_dirty_ps_const = device->d3d_pshader_constantF;
2351 else if (context->restore_ctx)
2353 context_set_gl_context(context);
2356 return context;