wined3d: Explicitly specify the resource location to context_attach_depth_stencil_fbo().
[wine.git] / dlls / wined3d / context.c
blobb4788bdb7c8b689ace5acd8db64e90f81bb17329
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 static 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 static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
116 GLenum fbo_target, struct wined3d_surface *depth_stencil, DWORD location)
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 (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 switch (location)
146 case SFLAG_INTEXTURE:
147 case SFLAG_INSRGBTEX:
148 surface_prepare_texture(depth_stencil, context, FALSE);
150 if (format_flags & WINED3DFMT_FLAG_DEPTH)
152 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
153 depth_stencil->texture_target, depth_stencil->texture_name,
154 depth_stencil->texture_level);
155 checkGLcall("glFramebufferTexture2D()");
158 if (format_flags & WINED3DFMT_FLAG_STENCIL)
160 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
161 depth_stencil->texture_target, depth_stencil->texture_name,
162 depth_stencil->texture_level);
163 checkGLcall("glFramebufferTexture2D()");
165 break;
167 default:
168 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
169 break;
173 if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
175 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
176 checkGLcall("glFramebufferTexture2D()");
179 if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
181 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
182 checkGLcall("glFramebufferTexture2D()");
185 else
187 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
188 checkGLcall("glFramebufferTexture2D()");
190 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
191 checkGLcall("glFramebufferTexture2D()");
195 /* GL locking is done by the caller */
196 static void context_attach_surface_fbo(struct wined3d_context *context,
197 GLenum fbo_target, DWORD idx, struct wined3d_surface *surface, DWORD location)
199 const struct wined3d_gl_info *gl_info = context->gl_info;
201 TRACE("Attach surface %p to %u\n", surface, idx);
203 if (surface && surface->resource.format->id != WINED3DFMT_NULL)
205 BOOL srgb;
207 switch (location)
209 case SFLAG_INTEXTURE:
210 case SFLAG_INSRGBTEX:
211 srgb = location == SFLAG_INSRGBTEX;
212 surface_prepare_texture(surface, context, srgb);
213 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
214 surface->texture_target, surface_get_texture_name(surface, gl_info, srgb),
215 surface->texture_level);
216 break;
218 default:
219 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
220 break;
222 checkGLcall("glFramebufferTexture2D()");
224 else
226 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
227 checkGLcall("glFramebufferTexture2D()");
231 /* GL locking is done by the caller */
232 void context_check_fbo_status(const struct wined3d_context *context, GLenum target)
234 const struct wined3d_gl_info *gl_info = context->gl_info;
235 GLenum status;
237 if (!FIXME_ON(d3d)) return;
239 status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
240 if (status == GL_FRAMEBUFFER_COMPLETE)
242 TRACE("FBO complete\n");
244 else
246 const struct wined3d_surface *attachment;
247 unsigned int i;
249 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
251 if (!context->current_fbo)
253 ERR("FBO 0 is incomplete, driver bug?\n");
254 return;
257 FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location),
258 context->current_fbo->location);
260 /* Dump the FBO attachments */
261 for (i = 0; i < gl_info->limits.buffers; ++i)
263 attachment = context->current_fbo->render_targets[i];
264 if (attachment)
266 FIXME("\tColor attachment %d: (%p) %s %ux%u %u samples.\n",
267 i, attachment, debug_d3dformat(attachment->resource.format->id),
268 attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
271 attachment = context->current_fbo->depth_stencil;
272 if (attachment)
274 FIXME("\tDepth attachment: (%p) %s %ux%u %u samples.\n",
275 attachment, debug_d3dformat(attachment->resource.format->id),
276 attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
281 static inline DWORD context_generate_rt_mask(GLenum buffer)
283 /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
284 return buffer ? (1 << 31) | buffer : 0;
287 static inline DWORD context_generate_rt_mask_from_surface(const struct wined3d_surface *target)
289 return (1 << 31) | surface_get_gl_buffer(target);
292 static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
293 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
295 const struct wined3d_gl_info *gl_info = context->gl_info;
296 struct fbo_entry *entry;
298 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
299 entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
300 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
301 entry->depth_stencil = depth_stencil;
302 entry->location = location;
303 entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
304 entry->attached = FALSE;
305 entry->id = 0;
307 return entry;
310 /* GL locking is done by the caller */
311 static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
312 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
313 DWORD location, struct fbo_entry *entry)
315 const struct wined3d_gl_info *gl_info = context->gl_info;
317 context_bind_fbo(context, target, &entry->id);
318 context_clean_fbo_attachments(gl_info, target);
320 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
321 entry->depth_stencil = depth_stencil;
322 entry->location = location;
323 entry->attached = FALSE;
326 /* GL locking is done by the caller */
327 static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
329 if (entry->id)
331 TRACE("Destroy FBO %d\n", entry->id);
332 context_destroy_fbo(context, &entry->id);
334 --context->fbo_entry_count;
335 list_remove(&entry->entry);
336 HeapFree(GetProcessHeap(), 0, entry->render_targets);
337 HeapFree(GetProcessHeap(), 0, entry);
341 /* GL locking is done by the caller */
342 static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
343 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
345 const struct wined3d_gl_info *gl_info = context->gl_info;
346 struct fbo_entry *entry;
348 if (depth_stencil && render_targets && render_targets[0])
350 if (depth_stencil->resource.width < render_targets[0]->resource.width ||
351 depth_stencil->resource.height < render_targets[0]->resource.height)
353 WARN("Depth stencil is smaller than the primary color buffer, disabling\n");
354 depth_stencil = NULL;
358 LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
360 if (!memcmp(entry->render_targets,
361 render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
362 && entry->depth_stencil == depth_stencil && entry->location == location)
364 list_remove(&entry->entry);
365 list_add_head(&context->fbo_list, &entry->entry);
366 return entry;
370 if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
372 entry = context_create_fbo_entry(context, render_targets, depth_stencil, location);
373 list_add_head(&context->fbo_list, &entry->entry);
374 ++context->fbo_entry_count;
376 else
378 entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
379 context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry);
380 list_remove(&entry->entry);
381 list_add_head(&context->fbo_list, &entry->entry);
384 return entry;
387 /* GL locking is done by the caller */
388 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
390 const struct wined3d_gl_info *gl_info = context->gl_info;
391 unsigned int i;
393 context_bind_fbo(context, target, &entry->id);
395 if (entry->attached) return;
397 /* Apply render targets */
398 for (i = 0; i < gl_info->limits.buffers; ++i)
400 context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location);
403 /* Apply depth targets */
404 if (entry->depth_stencil)
405 surface_set_compatible_renderbuffer(entry->depth_stencil, entry->render_targets[0]);
406 context_attach_depth_stencil_fbo(context, target, entry->depth_stencil, entry->location);
408 entry->attached = TRUE;
411 /* GL locking is done by the caller */
412 static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
413 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
415 struct fbo_entry *entry, *entry2;
417 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
419 context_destroy_fbo_entry(context, entry);
422 if (context->rebind_fbo)
424 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
425 context->rebind_fbo = FALSE;
428 if (location == SFLAG_INDRAWABLE)
430 context->current_fbo = NULL;
431 context_bind_fbo(context, target, NULL);
433 else
435 context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
436 context_apply_fbo_entry(context, target, context->current_fbo);
440 /* GL locking is done by the caller */
441 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
442 struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
444 UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets);
446 context->blit_targets[0] = render_target;
447 if (clear_size)
448 memset(&context->blit_targets[1], 0, clear_size);
449 context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location);
452 /* Context activation is done by the caller. */
453 void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
455 const struct wined3d_gl_info *gl_info = context->gl_info;
457 if (context->free_occlusion_query_count)
459 query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
461 else
463 if (gl_info->supported[ARB_OCCLUSION_QUERY])
465 ENTER_GL();
466 GL_EXTCALL(glGenQueriesARB(1, &query->id));
467 checkGLcall("glGenQueriesARB");
468 LEAVE_GL();
470 TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
472 else
474 WARN("Occlusion queries not supported, not allocating query id.\n");
475 query->id = 0;
479 query->context = context;
480 list_add_head(&context->occlusion_queries, &query->entry);
483 void context_free_occlusion_query(struct wined3d_occlusion_query *query)
485 struct wined3d_context *context = query->context;
487 list_remove(&query->entry);
488 query->context = NULL;
490 if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
492 UINT new_size = context->free_occlusion_query_size << 1;
493 GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
494 new_size * sizeof(*context->free_occlusion_queries));
496 if (!new_data)
498 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
499 return;
502 context->free_occlusion_query_size = new_size;
503 context->free_occlusion_queries = new_data;
506 context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
509 /* Context activation is done by the caller. */
510 void context_alloc_event_query(struct wined3d_context *context, struct wined3d_event_query *query)
512 const struct wined3d_gl_info *gl_info = context->gl_info;
514 if (context->free_event_query_count)
516 query->object = context->free_event_queries[--context->free_event_query_count];
518 else
520 if (gl_info->supported[ARB_SYNC])
522 /* Using ARB_sync, not much to do here. */
523 query->object.sync = NULL;
524 TRACE("Allocated event query %p in context %p.\n", query->object.sync, context);
526 else if (gl_info->supported[APPLE_FENCE])
528 ENTER_GL();
529 GL_EXTCALL(glGenFencesAPPLE(1, &query->object.id));
530 checkGLcall("glGenFencesAPPLE");
531 LEAVE_GL();
533 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
535 else if(gl_info->supported[NV_FENCE])
537 ENTER_GL();
538 GL_EXTCALL(glGenFencesNV(1, &query->object.id));
539 checkGLcall("glGenFencesNV");
540 LEAVE_GL();
542 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
544 else
546 WARN("Event queries not supported, not allocating query id.\n");
547 query->object.id = 0;
551 query->context = context;
552 list_add_head(&context->event_queries, &query->entry);
555 void context_free_event_query(struct wined3d_event_query *query)
557 struct wined3d_context *context = query->context;
559 list_remove(&query->entry);
560 query->context = NULL;
562 if (context->free_event_query_count >= context->free_event_query_size - 1)
564 UINT new_size = context->free_event_query_size << 1;
565 union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
566 new_size * sizeof(*context->free_event_queries));
568 if (!new_data)
570 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->object.id, context);
571 return;
574 context->free_event_query_size = new_size;
575 context->free_event_queries = new_data;
578 context->free_event_queries[context->free_event_query_count++] = query->object;
581 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
583 static void context_enum_surface_fbo_entries(const struct wined3d_device *device,
584 const struct wined3d_surface *surface, context_fbo_entry_func_t *callback)
586 UINT i;
588 for (i = 0; i < device->context_count; ++i)
590 struct wined3d_context *context = device->contexts[i];
591 const struct wined3d_gl_info *gl_info = context->gl_info;
592 struct fbo_entry *entry, *entry2;
594 if (context->current_rt == surface) context->current_rt = NULL;
596 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
598 UINT j;
600 if (entry->depth_stencil == surface)
602 callback(context, entry);
603 continue;
606 for (j = 0; j < gl_info->limits.buffers; ++j)
608 if (entry->render_targets[j] == surface)
610 callback(context, entry);
611 break;
618 static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
620 list_remove(&entry->entry);
621 list_add_head(&context->fbo_destroy_list, &entry->entry);
624 void context_resource_released(const struct wined3d_device *device,
625 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
627 if (!device->d3d_initialized) return;
629 switch (type)
631 case WINED3DRTYPE_SURFACE:
632 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
633 context_queue_fbo_entry_destruction);
634 break;
636 default:
637 break;
641 static void context_detach_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
643 entry->attached = FALSE;
646 void context_resource_unloaded(const struct wined3d_device *device,
647 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
649 switch (type)
651 case WINED3DRTYPE_SURFACE:
652 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
653 context_detach_fbo_entry);
654 break;
656 default:
657 break;
661 void context_surface_update(struct wined3d_context *context, const struct wined3d_surface *surface)
663 const struct wined3d_gl_info *gl_info = context->gl_info;
664 struct fbo_entry *entry = context->current_fbo;
665 unsigned int i;
667 if (!entry || context->rebind_fbo) return;
669 for (i = 0; i < gl_info->limits.buffers; ++i)
671 if (surface == entry->render_targets[i])
673 TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
674 context->rebind_fbo = TRUE;
675 return;
679 if (surface == entry->depth_stencil)
681 TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
682 context->rebind_fbo = TRUE;
686 static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
688 int current = GetPixelFormat(dc);
690 if (current == format) return TRUE;
692 if (!current)
694 if (!SetPixelFormat(dc, format, NULL))
696 ERR("Failed to set pixel format %d on device context %p, last error %#x.\n",
697 format, dc, GetLastError());
698 return FALSE;
700 return TRUE;
703 /* By default WGL doesn't allow pixel format adjustments but we need it
704 * here. For this reason there's a Wine specific wglSetPixelFormat()
705 * which allows us to set the pixel format multiple times. Only use it
706 * when really needed. */
707 if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
709 if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format, NULL)))
711 ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
712 format, dc);
713 return FALSE;
715 return TRUE;
718 /* OpenGL doesn't allow pixel format adjustments. Print an error and
719 * continue using the old format. There's a big chance that the old
720 * format works although with a performance hit and perhaps rendering
721 * errors. */
722 ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
723 format, dc, current);
724 return TRUE;
727 static BOOL context_set_gl_context(struct wined3d_context *ctx)
729 struct wined3d_swapchain *swapchain = ctx->swapchain;
731 if (!pwglMakeCurrent(ctx->hdc, ctx->glCtx))
733 HDC dc;
735 WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
736 ctx->glCtx, ctx->hdc, GetLastError());
737 ctx->valid = 0;
738 WARN("Trying fallback to the backup window.\n");
740 if (!(dc = swapchain_get_backup_dc(swapchain)))
742 context_set_current(NULL);
743 return FALSE;
746 if (!context_set_pixel_format(ctx->gl_info, dc, ctx->pixel_format))
748 ERR("Failed to set pixel format %d on device context %p.\n",
749 ctx->pixel_format, dc);
750 context_set_current(NULL);
751 return FALSE;
754 if (!pwglMakeCurrent(dc, ctx->glCtx))
756 ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
757 dc, GetLastError());
758 context_set_current(NULL);
759 return FALSE;
762 return TRUE;
765 static void context_restore_gl_context(HDC dc, HGLRC gl_ctx)
767 if (!pwglMakeCurrent(dc, gl_ctx))
769 ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
770 gl_ctx, dc, GetLastError());
771 context_set_current(NULL);
775 static void context_update_window(struct wined3d_context *context)
777 if (context->win_handle == context->swapchain->win_handle)
778 return;
780 TRACE("Updating context %p window from %p to %p.\n",
781 context, context->win_handle, context->swapchain->win_handle);
783 if (context->valid)
785 /* You'd figure ReleaseDC() would fail if the DC doesn't match the
786 * window. However, that's not what actually happens, and there are
787 * user32 tests that confirm ReleaseDC() with the wrong window is
788 * supposed to succeed. So explicitly check that the DC belongs to
789 * the window, since we want to avoid releasing a DC that belongs to
790 * some other window if the original window was already destroyed. */
791 if (WindowFromDC(context->hdc) != context->win_handle)
793 WARN("DC %p does not belong to window %p.\n",
794 context->hdc, context->win_handle);
796 else if (!ReleaseDC(context->win_handle, context->hdc))
798 ERR("Failed to release device context %p, last error %#x.\n",
799 context->hdc, GetLastError());
802 else context->valid = 1;
804 context->win_handle = context->swapchain->win_handle;
806 if (!(context->hdc = GetDC(context->win_handle)))
808 ERR("Failed to get a device context for window %p.\n", context->win_handle);
809 goto err;
812 if (!context_set_pixel_format(context->gl_info, context->hdc, context->pixel_format))
814 ERR("Failed to set pixel format %d on device context %p.\n",
815 context->pixel_format, context->hdc);
816 goto err;
819 context_set_gl_context(context);
821 return;
823 err:
824 context->valid = 0;
827 /* Do not call while under the GL lock. */
828 static void context_destroy_gl_resources(struct wined3d_context *context)
830 const struct wined3d_gl_info *gl_info = context->gl_info;
831 struct wined3d_occlusion_query *occlusion_query;
832 struct wined3d_event_query *event_query;
833 struct fbo_entry *entry, *entry2;
834 HGLRC restore_ctx;
835 HDC restore_dc;
836 unsigned int i;
838 restore_ctx = pwglGetCurrentContext();
839 restore_dc = pwglGetCurrentDC();
841 context_update_window(context);
842 if (context->valid && restore_ctx != context->glCtx)
843 context_set_gl_context(context);
844 else restore_ctx = NULL;
846 ENTER_GL();
848 LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
850 if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
851 GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
852 occlusion_query->context = NULL;
855 LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
857 if (context->valid)
859 if (gl_info->supported[ARB_SYNC])
861 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
863 else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
864 else if (gl_info->supported[NV_FENCE]) GL_EXTCALL(glDeleteFencesNV(1, &event_query->object.id));
866 event_query->context = NULL;
869 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
871 if (!context->valid) entry->id = 0;
872 context_destroy_fbo_entry(context, entry);
875 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
877 if (!context->valid) entry->id = 0;
878 context_destroy_fbo_entry(context, entry);
881 if (context->valid)
883 if (context->dummy_arbfp_prog)
885 GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
888 if (gl_info->supported[ARB_OCCLUSION_QUERY])
889 GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
891 if (gl_info->supported[ARB_SYNC])
893 for (i = 0; i < context->free_event_query_count; ++i)
895 GL_EXTCALL(glDeleteSync(context->free_event_queries[i].sync));
898 else if (gl_info->supported[APPLE_FENCE])
900 for (i = 0; i < context->free_event_query_count; ++i)
902 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_event_queries[i].id));
905 else if (gl_info->supported[NV_FENCE])
907 for (i = 0; i < context->free_event_query_count; ++i)
909 GL_EXTCALL(glDeleteFencesNV(1, &context->free_event_queries[i].id));
913 checkGLcall("context cleanup");
916 LEAVE_GL();
918 HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
919 HeapFree(GetProcessHeap(), 0, context->free_event_queries);
921 if (restore_ctx)
923 context_restore_gl_context(restore_dc, restore_ctx);
925 else if (pwglGetCurrentContext() && !pwglMakeCurrent(NULL, NULL))
927 ERR("Failed to disable GL context.\n");
930 ReleaseDC(context->win_handle, context->hdc);
932 if (!pwglDeleteContext(context->glCtx))
934 DWORD err = GetLastError();
935 ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
939 DWORD context_get_tls_idx(void)
941 return wined3d_context_tls_idx;
944 void context_set_tls_idx(DWORD idx)
946 wined3d_context_tls_idx = idx;
949 struct wined3d_context *context_get_current(void)
951 return TlsGetValue(wined3d_context_tls_idx);
954 /* Do not call while under the GL lock. */
955 BOOL context_set_current(struct wined3d_context *ctx)
957 struct wined3d_context *old = context_get_current();
959 if (old == ctx)
961 TRACE("Already using D3D context %p.\n", ctx);
962 return TRUE;
965 if (old)
967 if (old->destroyed)
969 TRACE("Switching away from destroyed context %p.\n", old);
970 context_destroy_gl_resources(old);
971 HeapFree(GetProcessHeap(), 0, old);
973 else
975 old->current = 0;
979 if (ctx)
981 if (!ctx->valid)
983 ERR("Trying to make invalid context %p current\n", ctx);
984 return FALSE;
987 TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
988 if (!context_set_gl_context(ctx))
989 return FALSE;
990 ctx->current = 1;
992 else if(pwglGetCurrentContext())
994 TRACE("Clearing current D3D context.\n");
995 if (!pwglMakeCurrent(NULL, NULL))
997 DWORD err = GetLastError();
998 ERR("Failed to clear current GL context, last error %#x.\n", err);
999 TlsSetValue(wined3d_context_tls_idx, NULL);
1000 return FALSE;
1004 return TlsSetValue(wined3d_context_tls_idx, ctx);
1007 void context_release(struct wined3d_context *context)
1009 TRACE("Releasing context %p, level %u.\n", context, context->level);
1011 if (WARN_ON(d3d))
1013 if (!context->level)
1014 WARN("Context %p is not active.\n", context);
1015 else if (context != context_get_current())
1016 WARN("Context %p is not the current context.\n", context);
1019 if (!--context->level && context->restore_ctx)
1021 TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1022 context_restore_gl_context(context->restore_dc, context->restore_ctx);
1023 context->restore_ctx = NULL;
1024 context->restore_dc = NULL;
1028 static void context_enter(struct wined3d_context *context)
1030 TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1032 if (!context->level++)
1034 const struct wined3d_context *current_context = context_get_current();
1035 HGLRC current_gl = pwglGetCurrentContext();
1037 if (current_gl && (!current_context || current_context->glCtx != current_gl))
1039 TRACE("Another GL context (%p on device context %p) is already current.\n",
1040 current_gl, pwglGetCurrentDC());
1041 context->restore_ctx = current_gl;
1042 context->restore_dc = pwglGetCurrentDC();
1047 void context_invalidate_state(struct wined3d_context *context, DWORD state)
1049 DWORD rep = context->state_table[state].representative;
1050 DWORD idx;
1051 BYTE shift;
1053 if (isStateDirty(context, rep)) return;
1055 context->dirtyArray[context->numDirtyEntries++] = rep;
1056 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1057 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1058 context->isStateDirty[idx] |= (1 << shift);
1061 /* This function takes care of wined3d pixel format selection. */
1062 static int context_choose_pixel_format(struct wined3d_device *device, HDC hdc,
1063 const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1064 BOOL auxBuffers, int numSamples, BOOL findCompatible)
1066 int iPixelFormat=0;
1067 unsigned int matchtry;
1068 BYTE redBits, greenBits, blueBits, alphaBits, colorBits;
1069 BYTE depthBits=0, stencilBits=0;
1071 static const struct
1073 BOOL require_aux;
1074 BOOL exact_alpha;
1075 BOOL exact_color;
1077 matches[] =
1079 /* First, try without alpha match buffers. MacOS supports aux buffers only
1080 * on A8R8G8B8, and we prefer better offscreen rendering over an alpha match.
1081 * Then try without aux buffers - this is the most common cause for not
1082 * finding a pixel format. Also some drivers(the open source ones)
1083 * only offer 32 bit ARB pixel formats. First try without an exact alpha
1084 * match, then try without an exact alpha and color match.
1086 { TRUE, TRUE, TRUE },
1087 { TRUE, FALSE, TRUE },
1088 { FALSE, TRUE, TRUE },
1089 { FALSE, FALSE, TRUE },
1090 { TRUE, FALSE, FALSE },
1091 { FALSE, FALSE, FALSE },
1094 int i = 0;
1095 int nCfgs = device->adapter->nCfgs;
1097 TRACE("ColorFormat=%s, DepthStencilFormat=%s, auxBuffers=%d, numSamples=%d, findCompatible=%d\n",
1098 debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1099 auxBuffers, numSamples, findCompatible);
1101 if (!getColorBits(color_format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits))
1103 ERR("Unable to get color bits for format %s (%#x)!\n",
1104 debug_d3dformat(color_format->id), color_format->id);
1105 return 0;
1108 getDepthStencilBits(ds_format, &depthBits, &stencilBits);
1110 for (matchtry = 0; matchtry < (sizeof(matches) / sizeof(*matches)) && !iPixelFormat; ++matchtry)
1112 for (i = 0; i < nCfgs; ++i)
1114 const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1115 BOOL exactDepthMatch = TRUE;
1117 /* For now only accept RGBA formats. Perhaps some day we will
1118 * allow floating point formats for pbuffers. */
1119 if(cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1120 continue;
1122 /* In window mode we need a window drawable format and double buffering. */
1123 if(!(cfg->windowDrawable && cfg->doubleBuffer))
1124 continue;
1126 /* We like to have aux buffers in backbuffer mode */
1127 if(auxBuffers && !cfg->auxBuffers && matches[matchtry].require_aux)
1128 continue;
1130 if(matches[matchtry].exact_color) {
1131 if(cfg->redSize != redBits)
1132 continue;
1133 if(cfg->greenSize != greenBits)
1134 continue;
1135 if(cfg->blueSize != blueBits)
1136 continue;
1137 } else {
1138 if(cfg->redSize < redBits)
1139 continue;
1140 if(cfg->greenSize < greenBits)
1141 continue;
1142 if(cfg->blueSize < blueBits)
1143 continue;
1145 if(matches[matchtry].exact_alpha) {
1146 if(cfg->alphaSize != alphaBits)
1147 continue;
1148 } else {
1149 if(cfg->alphaSize < alphaBits)
1150 continue;
1153 /* We try to locate a format which matches our requirements exactly. In case of
1154 * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1155 if(cfg->depthSize < depthBits)
1156 continue;
1157 else if(cfg->depthSize > depthBits)
1158 exactDepthMatch = FALSE;
1160 /* In all cases make sure the number of stencil bits matches our requirements
1161 * even when we don't need stencil because it could affect performance EXCEPT
1162 * on cards which don't offer depth formats without stencil like the i915 drivers
1163 * on Linux. */
1164 if (stencilBits != cfg->stencilSize
1165 && !(device->adapter->brokenStencil && stencilBits <= cfg->stencilSize))
1166 continue;
1168 /* Check multisampling support */
1169 if(cfg->numSamples != numSamples)
1170 continue;
1172 /* When we have passed all the checks then we have found a format which matches our
1173 * requirements. Note that we only check for a limit number of capabilities right now,
1174 * so there can easily be a dozen of pixel formats which appear to be the 'same' but
1175 * can still differ in things like multisampling, stereo, SRGB and other flags.
1178 /* Exit the loop as we have found a format :) */
1179 if(exactDepthMatch) {
1180 iPixelFormat = cfg->iPixelFormat;
1181 break;
1182 } else if(!iPixelFormat) {
1183 /* In the end we might end up with a format which doesn't exactly match our depth
1184 * requirements. Accept the first format we found because formats with higher iPixelFormat
1185 * values tend to have more extended capabilities (e.g. multisampling) which we don't need. */
1186 iPixelFormat = cfg->iPixelFormat;
1191 /* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
1192 if(!iPixelFormat && !findCompatible) {
1193 ERR("Can't find a suitable iPixelFormat\n");
1194 return FALSE;
1195 } else if(!iPixelFormat) {
1196 PIXELFORMATDESCRIPTOR pfd;
1198 TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
1199 /* PixelFormat selection */
1200 ZeroMemory(&pfd, sizeof(pfd));
1201 pfd.nSize = sizeof(pfd);
1202 pfd.nVersion = 1;
1203 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1204 pfd.iPixelType = PFD_TYPE_RGBA;
1205 pfd.cAlphaBits = alphaBits;
1206 pfd.cColorBits = colorBits;
1207 pfd.cDepthBits = depthBits;
1208 pfd.cStencilBits = stencilBits;
1209 pfd.iLayerType = PFD_MAIN_PLANE;
1211 iPixelFormat = ChoosePixelFormat(hdc, &pfd);
1212 if(!iPixelFormat) {
1213 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
1214 ERR("Can't find a suitable iPixelFormat\n");
1215 return FALSE;
1219 TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
1220 iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1221 return iPixelFormat;
1224 /* Do not call while under the GL lock. */
1225 struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
1226 struct wined3d_surface *target, const struct wined3d_format *ds_format)
1228 struct wined3d_device *device = swapchain->device;
1229 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1230 const struct wined3d_format *color_format;
1231 struct wined3d_context *ret;
1232 PIXELFORMATDESCRIPTOR pfd;
1233 BOOL auxBuffers = FALSE;
1234 int numSamples = 0;
1235 int pixel_format;
1236 unsigned int s;
1237 int swap_interval;
1238 DWORD state;
1239 HGLRC ctx;
1240 HDC hdc;
1242 TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1244 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1245 if (!ret)
1247 ERR("Failed to allocate context memory.\n");
1248 return NULL;
1251 if (!(hdc = GetDC(swapchain->win_handle)))
1253 WARN("Failed to retireve device context, trying swapchain backup.\n");
1255 if (!(hdc = swapchain_get_backup_dc(swapchain)))
1257 ERR("Failed to retrieve a device context.\n");
1258 goto out;
1262 color_format = target->resource.format;
1264 /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
1265 * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
1266 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
1268 auxBuffers = TRUE;
1270 if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
1271 color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM);
1272 else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
1273 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1276 /* DirectDraw supports 8bit paletted render targets and these are used by
1277 * old games like StarCraft and C&C. Most modern hardware doesn't support
1278 * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
1279 * conversion (ab)uses the alpha component for storing the palette index.
1280 * For this reason we require a format with 8bit alpha, so request
1281 * A8R8G8B8. */
1282 if (color_format->id == WINED3DFMT_P8_UINT)
1283 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1285 /* D3D only allows multisampling when SwapEffect is set to WINED3DSWAPEFFECT_DISCARD. */
1286 if (swapchain->presentParms.MultiSampleType && (swapchain->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD))
1288 if (!gl_info->supported[ARB_MULTISAMPLE])
1289 WARN("The application is requesting multisampling without support.\n");
1290 else
1292 TRACE("Requesting multisample type %#x.\n", swapchain->presentParms.MultiSampleType);
1293 numSamples = swapchain->presentParms.MultiSampleType;
1297 /* Try to find a pixel format which matches our requirements. */
1298 pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format,
1299 auxBuffers, numSamples, FALSE /* findCompatible */);
1301 /* Try to locate a compatible format if we weren't able to find anything. */
1302 if (!pixel_format)
1304 TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
1305 pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format,
1306 auxBuffers, 0 /* numSamples */, TRUE /* findCompatible */);
1309 /* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
1310 if (!pixel_format)
1312 ERR("Can't find a suitable pixel format.\n");
1313 goto out;
1316 DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd);
1317 if (!context_set_pixel_format(gl_info, hdc, pixel_format))
1319 ERR("Failed to set pixel format %d on device context %p.\n", pixel_format, hdc);
1320 goto out;
1323 ctx = pwglCreateContext(hdc);
1324 if (device->context_count)
1326 if (!pwglShareLists(device->contexts[0]->glCtx, ctx))
1328 DWORD err = GetLastError();
1329 ERR("wglShareLists(%p, %p) failed, last error %#x.\n",
1330 device->contexts[0]->glCtx, ctx, err);
1334 if(!ctx) {
1335 ERR("Failed to create a WGL context\n");
1336 goto out;
1339 if (!device_context_add(device, ret))
1341 ERR("Failed to add the newly created context to the context list\n");
1342 if (!pwglDeleteContext(ctx))
1344 DWORD err = GetLastError();
1345 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, err);
1347 goto out;
1350 ret->gl_info = gl_info;
1351 ret->state_table = device->StateTable;
1353 /* Mark all states dirty to force a proper initialization of the states
1354 * on the first use of the context. */
1355 for (state = 0; state <= STATE_HIGHEST; ++state)
1357 if (ret->state_table[state].representative)
1358 context_invalidate_state(ret, state);
1361 ret->swapchain = swapchain;
1362 ret->current_rt = target;
1363 ret->tid = GetCurrentThreadId();
1365 ret->render_offscreen = surface_is_offscreen(target);
1366 ret->draw_buffers_mask = context_generate_rt_mask(GL_BACK);
1367 ret->valid = 1;
1369 ret->glCtx = ctx;
1370 ret->win_handle = swapchain->win_handle;
1371 ret->hdc = hdc;
1372 ret->pixel_format = pixel_format;
1374 if (device->shader_backend->shader_dirtifyable_constants())
1376 /* Create the dirty constants array and initialize them to dirty */
1377 ret->vshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1378 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1379 ret->pshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1380 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1381 memset(ret->vshader_const_dirty, 1,
1382 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1383 memset(ret->pshader_const_dirty, 1,
1384 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1387 ret->blit_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1388 gl_info->limits.buffers * sizeof(*ret->blit_targets));
1389 if (!ret->blit_targets) goto out;
1391 ret->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1392 gl_info->limits.buffers * sizeof(*ret->draw_buffers));
1393 if (!ret->draw_buffers) goto out;
1395 ret->free_occlusion_query_size = 4;
1396 ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
1397 ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
1398 if (!ret->free_occlusion_queries) goto out;
1400 list_init(&ret->occlusion_queries);
1402 ret->free_event_query_size = 4;
1403 ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
1404 ret->free_event_query_size * sizeof(*ret->free_event_queries));
1405 if (!ret->free_event_queries) goto out;
1407 list_init(&ret->event_queries);
1409 TRACE("Successfully created new context %p\n", ret);
1411 list_init(&ret->fbo_list);
1412 list_init(&ret->fbo_destroy_list);
1414 context_enter(ret);
1416 /* Set up the context defaults */
1417 if (!context_set_current(ret))
1419 ERR("Cannot activate context to set up defaults\n");
1420 context_release(ret);
1421 goto out;
1424 switch (swapchain->presentParms.PresentationInterval)
1426 case WINED3DPRESENT_INTERVAL_IMMEDIATE:
1427 swap_interval = 0;
1428 break;
1429 case WINED3DPRESENT_INTERVAL_DEFAULT:
1430 case WINED3DPRESENT_INTERVAL_ONE:
1431 swap_interval = 1;
1432 break;
1433 case WINED3DPRESENT_INTERVAL_TWO:
1434 swap_interval = 2;
1435 break;
1436 case WINED3DPRESENT_INTERVAL_THREE:
1437 swap_interval = 3;
1438 break;
1439 case WINED3DPRESENT_INTERVAL_FOUR:
1440 swap_interval = 4;
1441 break;
1442 default:
1443 FIXME("Unknown presentation interval %08x\n", swapchain->presentParms.PresentationInterval);
1444 swap_interval = 1;
1447 if (gl_info->supported[WGL_EXT_SWAP_CONTROL])
1449 if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
1450 ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
1451 swap_interval, ret, GetLastError());
1454 ENTER_GL();
1456 glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
1458 TRACE("Setting up the screen\n");
1459 /* Clear the screen */
1460 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
1461 checkGLcall("glClearColor");
1462 glClearIndex(0);
1463 glClearDepth(1);
1464 glClearStencil(0xffff);
1466 checkGLcall("glClear");
1468 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1469 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1471 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1472 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1474 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1475 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1477 glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
1478 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
1479 glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);
1480 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
1482 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1484 /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
1485 * and textures in DIB sections(due to the memory protection).
1487 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1488 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1490 if (gl_info->supported[ARB_VERTEX_BLEND])
1492 /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one
1493 * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless
1494 * GL_VERTEX_BLEND_ARB isn't enabled too
1496 glEnable(GL_WEIGHT_SUM_UNITY_ARB);
1497 checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
1499 if (gl_info->supported[NV_TEXTURE_SHADER2])
1501 /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
1502 * the previous texture where to source the offset from is always unit - 1.
1504 for (s = 1; s < gl_info->limits.textures; ++s)
1506 context_active_texture(ret, gl_info, s);
1507 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
1508 checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
1511 if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
1513 /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
1514 * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
1515 * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
1516 * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
1517 * is ever assigned.
1519 * So make sure a program is assigned to each context. The first real ARBFP use will set a different
1520 * program and the dummy program is destroyed when the context is destroyed.
1522 const char *dummy_program =
1523 "!!ARBfp1.0\n"
1524 "MOV result.color, fragment.color.primary;\n"
1525 "END\n";
1526 GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
1527 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
1528 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
1531 if (gl_info->supported[ARB_POINT_SPRITE])
1533 for (s = 0; s < gl_info->limits.textures; ++s)
1535 context_active_texture(ret, gl_info, s);
1536 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
1537 checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
1541 if (gl_info->supported[ARB_PROVOKING_VERTEX])
1543 GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
1545 else if (gl_info->supported[EXT_PROVOKING_VERTEX])
1547 GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
1549 device->frag_pipe->enable_extension(TRUE);
1551 LEAVE_GL();
1553 TRACE("Created context %p.\n", ret);
1555 return ret;
1557 out:
1558 HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
1559 HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
1560 HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
1561 HeapFree(GetProcessHeap(), 0, ret->blit_targets);
1562 HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
1563 HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
1564 HeapFree(GetProcessHeap(), 0, ret);
1565 return NULL;
1568 /* Do not call while under the GL lock. */
1569 void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
1571 BOOL destroy;
1573 TRACE("Destroying ctx %p\n", context);
1575 if (context->tid == GetCurrentThreadId() || !context->current)
1577 context_destroy_gl_resources(context);
1578 TlsSetValue(wined3d_context_tls_idx, NULL);
1579 destroy = TRUE;
1581 else
1583 context->destroyed = 1;
1584 destroy = FALSE;
1587 HeapFree(GetProcessHeap(), 0, context->draw_buffers);
1588 HeapFree(GetProcessHeap(), 0, context->blit_targets);
1589 HeapFree(GetProcessHeap(), 0, context->vshader_const_dirty);
1590 HeapFree(GetProcessHeap(), 0, context->pshader_const_dirty);
1591 device_context_remove(device, context);
1592 if (destroy) HeapFree(GetProcessHeap(), 0, context);
1595 /* GL locking is done by the caller */
1596 static inline void set_blit_dimension(UINT width, UINT height) {
1597 glMatrixMode(GL_PROJECTION);
1598 checkGLcall("glMatrixMode(GL_PROJECTION)");
1599 glLoadIdentity();
1600 checkGLcall("glLoadIdentity()");
1601 glOrtho(0, width, 0, height, 0.0, -1.0);
1602 checkGLcall("glOrtho");
1603 glViewport(0, 0, width, height);
1604 checkGLcall("glViewport");
1607 /*****************************************************************************
1608 * SetupForBlit
1610 * Sets up a context for DirectDraw blitting.
1611 * All texture units are disabled, texture unit 0 is set as current unit
1612 * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
1613 * color writing enabled for all channels
1614 * register combiners disabled, shaders disabled
1615 * world matrix is set to identity, texture matrix 0 too
1616 * projection matrix is setup for drawing screen coordinates
1618 * Params:
1619 * This: Device to activate the context for
1620 * context: Context to setup
1622 *****************************************************************************/
1623 /* Context activation is done by the caller. */
1624 static void SetupForBlit(struct wined3d_device *device, struct wined3d_context *context)
1626 int i;
1627 const struct wined3d_gl_info *gl_info = context->gl_info;
1628 UINT width = context->current_rt->resource.width;
1629 UINT height = context->current_rt->resource.height;
1630 DWORD sampler;
1632 TRACE("Setting up context %p for blitting\n", context);
1633 if(context->last_was_blit) {
1634 if(context->blit_w != width || context->blit_h != height) {
1635 ENTER_GL();
1636 set_blit_dimension(width, height);
1637 LEAVE_GL();
1638 context->blit_w = width; context->blit_h = height;
1639 /* No need to dirtify here, the states are still dirtified because they weren't
1640 * applied since the last SetupForBlit call. Otherwise last_was_blit would not
1641 * be set
1644 TRACE("Context is already set up for blitting, nothing to do\n");
1645 return;
1647 context->last_was_blit = TRUE;
1649 /* TODO: Use a display list */
1651 /* Disable shaders */
1652 ENTER_GL();
1653 device->shader_backend->shader_select(context, FALSE, FALSE);
1654 LEAVE_GL();
1656 context_invalidate_state(context, STATE_VSHADER);
1657 context_invalidate_state(context, STATE_PIXELSHADER);
1659 /* Call ENTER_GL() once for all gl calls below. In theory we should not call
1660 * helper functions in between gl calls. This function is full of context_invalidate_state
1661 * which can safely be called from here, we only lock once instead locking/unlocking
1662 * after each GL call.
1664 ENTER_GL();
1666 /* Disable all textures. The caller can then bind a texture it wants to blit
1667 * from
1669 * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
1670 * function texture unit. No need to care for higher samplers
1672 for (i = gl_info->limits.textures - 1; i > 0 ; --i)
1674 sampler = device->rev_tex_unit_map[i];
1675 context_active_texture(context, gl_info, i);
1677 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1679 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1680 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1682 glDisable(GL_TEXTURE_3D);
1683 checkGLcall("glDisable GL_TEXTURE_3D");
1684 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1686 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1687 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1689 glDisable(GL_TEXTURE_2D);
1690 checkGLcall("glDisable GL_TEXTURE_2D");
1692 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1693 checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
1695 if (sampler != WINED3D_UNMAPPED_STAGE)
1697 if (sampler < MAX_TEXTURES)
1698 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP));
1699 context_invalidate_state(context, STATE_SAMPLER(sampler));
1702 context_active_texture(context, gl_info, 0);
1704 sampler = device->rev_tex_unit_map[0];
1706 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1708 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1709 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1711 glDisable(GL_TEXTURE_3D);
1712 checkGLcall("glDisable GL_TEXTURE_3D");
1713 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1715 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1716 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1718 glDisable(GL_TEXTURE_2D);
1719 checkGLcall("glDisable GL_TEXTURE_2D");
1721 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1723 glMatrixMode(GL_TEXTURE);
1724 checkGLcall("glMatrixMode(GL_TEXTURE)");
1725 glLoadIdentity();
1726 checkGLcall("glLoadIdentity()");
1728 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1730 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1731 GL_TEXTURE_LOD_BIAS_EXT,
1732 0.0f);
1733 checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
1736 if (sampler != WINED3D_UNMAPPED_STAGE)
1738 if (sampler < MAX_TEXTURES)
1740 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + sampler));
1741 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP));
1743 context_invalidate_state(context, STATE_SAMPLER(sampler));
1746 /* Other misc states */
1747 glDisable(GL_ALPHA_TEST);
1748 checkGLcall("glDisable(GL_ALPHA_TEST)");
1749 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHATESTENABLE));
1750 glDisable(GL_LIGHTING);
1751 checkGLcall("glDisable GL_LIGHTING");
1752 context_invalidate_state(context, STATE_RENDER(WINED3DRS_LIGHTING));
1753 glDisable(GL_DEPTH_TEST);
1754 checkGLcall("glDisable GL_DEPTH_TEST");
1755 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ZENABLE));
1756 glDisableWINE(GL_FOG);
1757 checkGLcall("glDisable GL_FOG");
1758 context_invalidate_state(context, STATE_RENDER(WINED3DRS_FOGENABLE));
1759 glDisable(GL_BLEND);
1760 checkGLcall("glDisable GL_BLEND");
1761 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
1762 glDisable(GL_CULL_FACE);
1763 checkGLcall("glDisable GL_CULL_FACE");
1764 context_invalidate_state(context, STATE_RENDER(WINED3DRS_CULLMODE));
1765 glDisable(GL_STENCIL_TEST);
1766 checkGLcall("glDisable GL_STENCIL_TEST");
1767 context_invalidate_state(context, STATE_RENDER(WINED3DRS_STENCILENABLE));
1768 glDisable(GL_SCISSOR_TEST);
1769 checkGLcall("glDisable GL_SCISSOR_TEST");
1770 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
1771 if (gl_info->supported[ARB_POINT_SPRITE])
1773 glDisable(GL_POINT_SPRITE_ARB);
1774 checkGLcall("glDisable GL_POINT_SPRITE_ARB");
1775 context_invalidate_state(context, STATE_RENDER(WINED3DRS_POINTSPRITEENABLE));
1777 glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
1778 checkGLcall("glColorMask");
1779 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
1780 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
1781 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
1782 context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
1783 if (gl_info->supported[EXT_SECONDARY_COLOR])
1785 glDisable(GL_COLOR_SUM_EXT);
1786 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SPECULARENABLE));
1787 checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
1790 /* Setup transforms */
1791 glMatrixMode(GL_MODELVIEW);
1792 checkGLcall("glMatrixMode(GL_MODELVIEW)");
1793 glLoadIdentity();
1794 checkGLcall("glLoadIdentity()");
1795 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)));
1797 context->last_was_rhw = TRUE;
1798 context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
1800 glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
1801 glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
1802 glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
1803 glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
1804 glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
1805 glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
1806 context_invalidate_state(context, STATE_RENDER(WINED3DRS_CLIPPING));
1808 set_blit_dimension(width, height);
1809 device->frag_pipe->enable_extension(FALSE);
1811 LEAVE_GL();
1813 context->blit_w = width; context->blit_h = height;
1814 context_invalidate_state(context, STATE_VIEWPORT);
1815 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_PROJECTION));
1818 static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
1820 return rt_mask & (1 << 31);
1823 static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
1825 return rt_mask & ~(1 << 31);
1828 /* Context activation and GL locking are done by the caller. */
1829 static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
1831 if (!rt_mask)
1833 glDrawBuffer(GL_NONE);
1834 checkGLcall("glDrawBuffer()");
1836 else if (is_rt_mask_onscreen(rt_mask))
1838 glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
1839 checkGLcall("glDrawBuffer()");
1841 else
1843 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
1845 const struct wined3d_gl_info *gl_info = context->gl_info;
1846 unsigned int i = 0;
1848 while (rt_mask)
1850 if (rt_mask & 1)
1851 context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
1852 else
1853 context->draw_buffers[i] = GL_NONE;
1855 rt_mask >>= 1;
1856 ++i;
1859 if (gl_info->supported[ARB_DRAW_BUFFERS])
1861 GL_EXTCALL(glDrawBuffersARB(i, context->draw_buffers));
1862 checkGLcall("glDrawBuffers()");
1864 else
1866 glDrawBuffer(context->draw_buffers[0]);
1867 checkGLcall("glDrawBuffer()");
1870 else
1872 ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
1877 /* GL locking is done by the caller. */
1878 void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
1880 glDrawBuffer(buffer);
1881 checkGLcall("glDrawBuffer()");
1882 if (context->current_fbo)
1883 context->current_fbo->rt_mask = context_generate_rt_mask(buffer);
1884 else
1885 context->draw_buffers_mask = context_generate_rt_mask(buffer);
1888 /* GL locking is done by the caller. */
1889 void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
1891 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0 + unit));
1892 checkGLcall("glActiveTextureARB");
1893 context->active_texture = unit;
1896 static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
1898 if (context->render_offscreen == offscreen) return;
1900 context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
1901 context_invalidate_state(context, STATE_TRANSFORM(WINED3DTS_PROJECTION));
1902 context_invalidate_state(context, STATE_VIEWPORT);
1903 context_invalidate_state(context, STATE_SCISSORRECT);
1904 context_invalidate_state(context, STATE_FRONTFACE);
1905 context->render_offscreen = offscreen;
1908 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
1909 const struct wined3d_format *required)
1911 BYTE existing_depth, existing_stencil, required_depth, required_stencil;
1913 if (existing == required) return TRUE;
1914 if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
1916 getDepthStencilBits(existing, &existing_depth, &existing_stencil);
1917 getDepthStencilBits(required, &required_depth, &required_stencil);
1919 if(existing_depth < required_depth) return FALSE;
1920 /* If stencil bits are used the exact amount is required - otherwise wrapping
1921 * won't work correctly */
1922 if(required_stencil && required_stencil != existing_stencil) return FALSE;
1923 return TRUE;
1926 /* The caller provides a context */
1927 static void context_validate_onscreen_formats(struct wined3d_context *context,
1928 const struct wined3d_surface *depth_stencil)
1930 /* Onscreen surfaces are always in a swapchain */
1931 struct wined3d_swapchain *swapchain = context->current_rt->container.u.swapchain;
1933 if (context->render_offscreen || !depth_stencil) return;
1934 if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format)) return;
1936 /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
1937 * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
1938 * format. */
1939 WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
1941 /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
1942 surface_load_location(context->current_rt, SFLAG_INTEXTURE, NULL);
1943 swapchain->render_to_fbo = TRUE;
1944 swapchain_update_draw_bindings(swapchain);
1945 context_set_render_offscreen(context, TRUE);
1948 static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_device *device, const struct wined3d_surface *rt)
1950 if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
1951 return 0;
1952 else if (rt->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1953 return context_generate_rt_mask_from_surface(rt);
1954 else
1955 return context_generate_rt_mask(device->offscreenBuffer);
1958 /* Context activation is done by the caller. */
1959 void context_apply_blit_state(struct wined3d_context *context, struct wined3d_device *device)
1961 struct wined3d_surface *rt = context->current_rt;
1962 DWORD rt_mask, old_mask;
1964 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
1966 context_validate_onscreen_formats(context, NULL);
1968 if (context->render_offscreen)
1970 surface_internal_preload(rt, SRGB_RGB);
1972 ENTER_GL();
1973 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, rt, NULL, rt->draw_binding);
1974 LEAVE_GL();
1975 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
1976 rt_mask = 1;
1977 else
1978 rt_mask = 0;
1980 else
1982 ENTER_GL();
1983 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
1984 LEAVE_GL();
1985 rt_mask = context_generate_rt_mask_from_surface(rt);
1988 else
1990 rt_mask = context_generate_rt_mask_no_fbo(device, rt);
1993 old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
1995 ENTER_GL();
1996 if (rt_mask != old_mask)
1998 context_apply_draw_buffers(context, rt_mask);
1999 context->draw_buffers_mask = rt_mask;
2002 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2004 context_check_fbo_status(context, GL_FRAMEBUFFER);
2006 LEAVE_GL();
2008 SetupForBlit(device, context);
2009 context_invalidate_state(context, STATE_FRAMEBUFFER);
2012 static BOOL context_validate_rt_config(UINT rt_count,
2013 struct wined3d_surface * const *rts, const struct wined3d_surface *ds)
2015 unsigned int i;
2017 if (ds) return TRUE;
2019 for (i = 0; i < rt_count; ++i)
2021 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2022 return TRUE;
2025 WARN("Invalid render target config, need at least one attachment.\n");
2026 return FALSE;
2029 /* Context activation is done by the caller. */
2030 BOOL context_apply_clear_state(struct wined3d_context *context, struct wined3d_device *device,
2031 UINT rt_count, const struct wined3d_fb_state *fb)
2033 DWORD rt_mask = 0, old_mask;
2034 UINT i;
2035 struct wined3d_surface **rts = fb->render_targets;
2037 if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != &device->fb
2038 || rt_count != context->gl_info->limits.buffers)
2040 if (!context_validate_rt_config(rt_count, rts, fb->depth_stencil))
2041 return FALSE;
2043 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2045 context_validate_onscreen_formats(context, fb->depth_stencil);
2047 ENTER_GL();
2049 if (!rt_count || surface_is_offscreen(rts[0]))
2051 for (i = 0; i < rt_count; ++i)
2053 context->blit_targets[i] = rts[i];
2054 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2055 rt_mask |= (1 << i);
2057 while (i < context->gl_info->limits.buffers)
2059 context->blit_targets[i] = NULL;
2060 ++i;
2062 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, fb->depth_stencil, SFLAG_INTEXTURE);
2063 glReadBuffer(GL_NONE);
2064 checkGLcall("glReadBuffer");
2066 else
2068 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2069 rt_mask = context_generate_rt_mask_from_surface(rts[0]);
2072 LEAVE_GL();
2074 /* If the framebuffer is not the device's fb the device's fb has to be reapplied
2075 * next draw. Otherwise we could mark the framebuffer state clean here, once the
2076 * state management allows this */
2077 context_invalidate_state(context, STATE_FRAMEBUFFER);
2079 else
2081 rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
2084 else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2085 && (!rt_count || surface_is_offscreen(rts[0])))
2087 for (i = 0; i < rt_count; ++i)
2089 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) rt_mask |= (1 << i);
2092 else
2094 rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
2097 old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
2099 ENTER_GL();
2100 if (rt_mask != old_mask)
2102 context_apply_draw_buffers(context, rt_mask);
2103 context->draw_buffers_mask = rt_mask;
2104 context_invalidate_state(context, STATE_FRAMEBUFFER);
2107 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2109 context_check_fbo_status(context, GL_FRAMEBUFFER);
2112 if (context->last_was_blit)
2114 device->frag_pipe->enable_extension(TRUE);
2115 context->last_was_blit = FALSE;
2118 /* Blending and clearing should be orthogonal, but tests on the nvidia
2119 * driver show that disabling blending when clearing improves the clearing
2120 * performance incredibly. */
2121 glDisable(GL_BLEND);
2122 glEnable(GL_SCISSOR_TEST);
2123 checkGLcall("glEnable GL_SCISSOR_TEST");
2124 LEAVE_GL();
2126 context_invalidate_state(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
2127 context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
2128 context_invalidate_state(context, STATE_SCISSORRECT);
2130 return TRUE;
2133 static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device)
2135 const struct wined3d_state *state = &device->stateBlock->state;
2136 struct wined3d_surface **rts = state->fb->render_targets;
2137 struct wined3d_shader *ps = state->pixel_shader;
2138 DWORD rt_mask, rt_mask_bits;
2139 unsigned int i;
2141 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return context_generate_rt_mask_no_fbo(device, rts[0]);
2142 else if (!context->render_offscreen) return context_generate_rt_mask_from_surface(rts[0]);
2144 rt_mask = ps ? ps->reg_maps.rt_mask : 1;
2145 rt_mask &= device->valid_rt_mask;
2146 rt_mask_bits = rt_mask;
2147 i = 0;
2148 while (rt_mask_bits)
2150 rt_mask_bits &= ~(1 << i);
2151 if (!rts[i] || rts[i]->resource.format->id == WINED3DFMT_NULL)
2152 rt_mask &= ~(1 << i);
2154 i++;
2157 return rt_mask;
2160 /* GL locking and context activation are done by the caller */
2161 void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
2163 const struct wined3d_device *device = context->swapchain->device;
2164 const struct wined3d_fb_state *fb = state->fb;
2165 DWORD rt_mask = find_draw_buffers_mask(context, device);
2166 DWORD old_mask;
2168 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2170 if (!context->render_offscreen)
2172 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2174 else
2176 context_apply_fbo_state(context, GL_FRAMEBUFFER, fb->render_targets, fb->depth_stencil, SFLAG_INTEXTURE);
2177 glReadBuffer(GL_NONE);
2178 checkGLcall("glReadBuffer");
2182 old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
2183 if (rt_mask != old_mask)
2185 context_apply_draw_buffers(context, rt_mask);
2186 context->draw_buffers_mask = rt_mask;
2190 /* GL locking and context activation are done by the caller */
2191 void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
2193 const struct wined3d_device *device = context->swapchain->device;
2194 DWORD rt_mask, old_mask;
2196 if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
2198 old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
2199 rt_mask = find_draw_buffers_mask(context, device);
2200 if (rt_mask != old_mask)
2202 context_apply_draw_buffers(context, rt_mask);
2203 context->draw_buffers_mask = rt_mask;
2207 /* Context activation is done by the caller. */
2208 BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
2210 const struct wined3d_state *state = &device->stateBlock->state;
2211 const struct StateEntry *state_table = context->state_table;
2212 const struct wined3d_fb_state *fb = state->fb;
2213 unsigned int i;
2215 if (!context_validate_rt_config(context->gl_info->limits.buffers,
2216 fb->render_targets, fb->depth_stencil))
2217 return FALSE;
2219 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
2221 context_validate_onscreen_formats(context, fb->depth_stencil);
2224 /* Preload resources before FBO setup. Texture preload in particular may
2225 * result in changes to the current FBO, due to using e.g. FBO blits for
2226 * updating a resource location. */
2227 device_update_tex_unit_map(device);
2228 device_preload_textures(device);
2229 if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC))
2230 device_update_stream_info(device, context->gl_info);
2232 ENTER_GL();
2233 if (context->last_was_blit)
2235 device->frag_pipe->enable_extension(TRUE);
2238 for (i = 0; i < context->numDirtyEntries; ++i)
2240 DWORD rep = context->dirtyArray[i];
2241 DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
2242 BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
2243 context->isStateDirty[idx] &= ~(1 << shift);
2244 state_table[rep].apply(context, state, rep);
2247 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2249 context_check_fbo_status(context, GL_FRAMEBUFFER);
2252 LEAVE_GL();
2253 context->numDirtyEntries = 0; /* This makes the whole list clean */
2254 context->last_was_blit = FALSE;
2256 return TRUE;
2259 static void context_setup_target(struct wined3d_device *device,
2260 struct wined3d_context *context, struct wined3d_surface *target)
2262 BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
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));
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));
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));
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, 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 if (current_context && current_context->destroyed)
2321 current_context = NULL;
2323 if (!target)
2325 if (current_context
2326 && current_context->current_rt
2327 && current_context->swapchain->device == device)
2329 target = current_context->current_rt;
2331 else
2333 struct wined3d_swapchain *swapchain = device->swapchains[0];
2334 if (swapchain->back_buffers)
2335 target = swapchain->back_buffers[0];
2336 else
2337 target = swapchain->front_buffer;
2341 if (current_context && current_context->current_rt == target)
2343 context = current_context;
2345 else if (target->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2347 TRACE("Rendering onscreen.\n");
2349 context = swapchain_get_context(target->container.u.swapchain);
2351 else
2353 TRACE("Rendering offscreen.\n");
2355 /* Stay with the current context if possible. Otherwise use the
2356 * context for the primary swapchain. */
2357 if (current_context && current_context->swapchain->device == device)
2358 context = current_context;
2359 else
2360 context = swapchain_get_context(device->swapchains[0]);
2363 context_update_window(context);
2364 context_setup_target(device, context, target);
2365 context_enter(context);
2366 if (!context->valid) return context;
2368 if (context != current_context)
2370 if (!context_set_current(context))
2372 ERR("Failed to activate the new context.\n");
2374 else
2376 ENTER_GL();
2377 device->frag_pipe->enable_extension(!context->last_was_blit);
2378 LEAVE_GL();
2381 if (context->vshader_const_dirty)
2383 memset(context->vshader_const_dirty, 1,
2384 sizeof(*context->vshader_const_dirty) * device->d3d_vshader_constantF);
2385 device->highest_dirty_vs_const = device->d3d_vshader_constantF;
2387 if (context->pshader_const_dirty)
2389 memset(context->pshader_const_dirty, 1,
2390 sizeof(*context->pshader_const_dirty) * device->d3d_pshader_constantF);
2391 device->highest_dirty_ps_const = device->d3d_pshader_constantF;
2394 else if (context->restore_ctx)
2396 context_set_gl_context(context);
2399 return context;