wined3d: Store all the resource desc information in struct wined3d_resource.
[wine.git] / dlls / wined3d / context.c
blob624f507c037c21ecf21c852e03ca1aedafb58eed
1 /*
2 * Context and render target management in wined3d
4 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
5 * Copyright 2009-2010 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 static void context_apply_attachment_filter_states(const struct wined3d_context *context,
116 IWineD3DSurfaceImpl *surface, DWORD location)
118 /* Update base texture states array */
119 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
121 IWineD3DBaseTextureImpl *texture = surface->container.u.texture;
122 IWineD3DDeviceImpl *device = surface->resource.device;
123 BOOL update_minfilter = FALSE;
124 BOOL update_magfilter = FALSE;
125 struct gl_texture *gl_tex;
127 switch (location)
129 case SFLAG_INTEXTURE:
130 case SFLAG_INSRGBTEX:
131 gl_tex = basetexture_get_gl_texture(texture,
132 context->gl_info, location == SFLAG_INSRGBTEX);
133 break;
135 default:
136 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
137 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
138 return;
141 if (gl_tex->states[WINED3DTEXSTA_MINFILTER] != WINED3DTEXF_POINT
142 || gl_tex->states[WINED3DTEXSTA_MIPFILTER] != WINED3DTEXF_NONE)
144 gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
145 gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
146 update_minfilter = TRUE;
149 if (gl_tex->states[WINED3DTEXSTA_MAGFILTER] != WINED3DTEXF_POINT)
151 gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
152 update_magfilter = TRUE;
155 if (texture->baseTexture.bindCount)
157 WARN("Render targets should not be bound to a sampler\n");
158 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(texture->baseTexture.sampler));
161 if (update_minfilter || update_magfilter)
163 GLenum target, bind_target;
164 GLint old_binding;
166 target = surface->texture_target;
167 if (target == GL_TEXTURE_2D)
169 bind_target = GL_TEXTURE_2D;
170 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
172 else if (target == GL_TEXTURE_RECTANGLE_ARB)
174 bind_target = GL_TEXTURE_RECTANGLE_ARB;
175 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
177 else
179 bind_target = GL_TEXTURE_CUBE_MAP_ARB;
180 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
183 glBindTexture(bind_target, gl_tex->name);
184 if (update_minfilter) glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 if (update_magfilter) glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
186 glBindTexture(bind_target, old_binding);
189 checkGLcall("apply_attachment_filter_states()");
193 /* GL locking is done by the caller */
194 void context_attach_depth_stencil_fbo(struct wined3d_context *context,
195 GLenum fbo_target, IWineD3DSurfaceImpl *depth_stencil, BOOL use_render_buffer)
197 const struct wined3d_gl_info *gl_info = context->gl_info;
199 TRACE("Attach depth stencil %p\n", depth_stencil);
201 if (depth_stencil)
203 DWORD format_flags = depth_stencil->resource.format->flags;
205 if (use_render_buffer && depth_stencil->current_renderbuffer)
207 if (format_flags & WINED3DFMT_FLAG_DEPTH)
209 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT,
210 GL_RENDERBUFFER, depth_stencil->current_renderbuffer->id);
211 checkGLcall("glFramebufferRenderbuffer()");
214 if (format_flags & WINED3DFMT_FLAG_STENCIL)
216 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT,
217 GL_RENDERBUFFER, depth_stencil->current_renderbuffer->id);
218 checkGLcall("glFramebufferRenderbuffer()");
221 else
223 surface_prepare_texture(depth_stencil, gl_info, FALSE);
224 context_apply_attachment_filter_states(context, depth_stencil, SFLAG_INTEXTURE);
226 if (format_flags & WINED3DFMT_FLAG_DEPTH)
228 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
229 depth_stencil->texture_target, depth_stencil->texture_name,
230 depth_stencil->texture_level);
231 checkGLcall("glFramebufferTexture2D()");
234 if (format_flags & WINED3DFMT_FLAG_STENCIL)
236 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
237 depth_stencil->texture_target, depth_stencil->texture_name,
238 depth_stencil->texture_level);
239 checkGLcall("glFramebufferTexture2D()");
243 if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
245 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
246 checkGLcall("glFramebufferTexture2D()");
249 if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
251 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
252 checkGLcall("glFramebufferTexture2D()");
255 else
257 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
258 checkGLcall("glFramebufferTexture2D()");
260 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
261 checkGLcall("glFramebufferTexture2D()");
265 /* GL locking is done by the caller */
266 static void context_attach_surface_fbo(const struct wined3d_context *context,
267 GLenum fbo_target, DWORD idx, IWineD3DSurfaceImpl *surface, DWORD location)
269 const struct wined3d_gl_info *gl_info = context->gl_info;
271 TRACE("Attach surface %p to %u\n", surface, idx);
273 if (surface && surface->resource.format->id != WINED3DFMT_NULL)
275 BOOL srgb;
277 switch (location)
279 case SFLAG_INTEXTURE:
280 case SFLAG_INSRGBTEX:
281 srgb = location == SFLAG_INSRGBTEX;
282 surface_prepare_texture(surface, gl_info, srgb);
283 context_apply_attachment_filter_states(context, surface, location);
284 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
285 surface->texture_target, surface_get_texture_name(surface, gl_info, srgb),
286 surface->texture_level);
287 break;
289 default:
290 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
291 break;
293 checkGLcall("glFramebufferTexture2D()");
295 else
297 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
298 checkGLcall("glFramebufferTexture2D()");
302 /* GL locking is done by the caller */
303 static void context_check_fbo_status(struct wined3d_context *context, GLenum target)
305 const struct wined3d_gl_info *gl_info = context->gl_info;
306 GLenum status;
308 status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
309 if (status == GL_FRAMEBUFFER_COMPLETE)
311 TRACE("FBO complete\n");
312 } else {
313 IWineD3DSurfaceImpl *attachment;
314 unsigned int i;
315 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
317 if (!context->current_fbo)
319 ERR("FBO 0 is incomplete, driver bug?\n");
320 return;
323 FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location),
324 context->current_fbo->location);
326 /* Dump the FBO attachments */
327 for (i = 0; i < gl_info->limits.buffers; ++i)
329 attachment = context->current_fbo->render_targets[i];
330 if (attachment)
332 FIXME("\tColor attachment %d: (%p) %s %ux%u\n",
333 i, attachment, debug_d3dformat(attachment->resource.format->id),
334 attachment->pow2Width, attachment->pow2Height);
337 attachment = context->current_fbo->depth_stencil;
338 if (attachment)
340 FIXME("\tDepth attachment: (%p) %s %ux%u\n",
341 attachment, debug_d3dformat(attachment->resource.format->id),
342 attachment->pow2Width, attachment->pow2Height);
347 static struct fbo_entry *context_create_fbo_entry(struct wined3d_context *context,
348 IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location)
350 const struct wined3d_gl_info *gl_info = context->gl_info;
351 struct fbo_entry *entry;
353 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
354 entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
355 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
356 entry->depth_stencil = depth_stencil;
357 entry->location = location;
358 entry->attached = FALSE;
359 entry->id = 0;
361 return entry;
364 /* GL locking is done by the caller */
365 static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
366 IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil,
367 DWORD location, struct fbo_entry *entry)
369 const struct wined3d_gl_info *gl_info = context->gl_info;
371 context_bind_fbo(context, target, &entry->id);
372 context_clean_fbo_attachments(gl_info, target);
374 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
375 entry->depth_stencil = depth_stencil;
376 entry->location = location;
377 entry->attached = FALSE;
380 /* GL locking is done by the caller */
381 static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
383 if (entry->id)
385 TRACE("Destroy FBO %d\n", entry->id);
386 context_destroy_fbo(context, &entry->id);
388 --context->fbo_entry_count;
389 list_remove(&entry->entry);
390 HeapFree(GetProcessHeap(), 0, entry->render_targets);
391 HeapFree(GetProcessHeap(), 0, entry);
395 /* GL locking is done by the caller */
396 static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
397 IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location)
399 const struct wined3d_gl_info *gl_info = context->gl_info;
400 struct fbo_entry *entry;
402 LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
404 if (!memcmp(entry->render_targets,
405 render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
406 && entry->depth_stencil == depth_stencil && entry->location == location)
408 list_remove(&entry->entry);
409 list_add_head(&context->fbo_list, &entry->entry);
410 return entry;
414 if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
416 entry = context_create_fbo_entry(context, render_targets, depth_stencil, location);
417 list_add_head(&context->fbo_list, &entry->entry);
418 ++context->fbo_entry_count;
420 else
422 entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
423 context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry);
424 list_remove(&entry->entry);
425 list_add_head(&context->fbo_list, &entry->entry);
428 return entry;
431 /* GL locking is done by the caller */
432 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
434 const struct wined3d_gl_info *gl_info = context->gl_info;
435 unsigned int i;
437 context_bind_fbo(context, target, &entry->id);
439 if (!entry->attached)
441 /* Apply render targets */
442 for (i = 0; i < gl_info->limits.buffers; ++i)
444 context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location);
447 /* Apply depth targets */
448 if (entry->depth_stencil)
450 surface_set_compatible_renderbuffer(entry->depth_stencil,
451 entry->render_targets[0]->pow2Width, entry->render_targets[0]->pow2Height);
453 context_attach_depth_stencil_fbo(context, target, entry->depth_stencil, TRUE);
455 entry->attached = TRUE;
457 else
459 for (i = 0; i < gl_info->limits.buffers; ++i)
461 if (entry->render_targets[i])
462 context_apply_attachment_filter_states(context, entry->render_targets[i], entry->location);
464 if (entry->depth_stencil)
465 context_apply_attachment_filter_states(context, entry->depth_stencil, SFLAG_INTEXTURE);
469 /* GL locking is done by the caller */
470 static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
471 IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location)
473 struct fbo_entry *entry, *entry2;
475 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
477 context_destroy_fbo_entry(context, entry);
480 if (context->rebind_fbo)
482 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
483 context->rebind_fbo = FALSE;
486 if (render_targets)
488 context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
489 context_apply_fbo_entry(context, target, context->current_fbo);
491 else
493 context->current_fbo = NULL;
494 context_bind_fbo(context, target, NULL);
497 context_check_fbo_status(context, target);
500 /* GL locking is done by the caller */
501 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
502 IWineD3DSurfaceImpl *render_target, IWineD3DSurfaceImpl *depth_stencil, DWORD location)
504 if (location != SFLAG_INDRAWABLE || surface_is_offscreen(render_target))
506 UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets);
507 context->blit_targets[0] = render_target;
508 if (clear_size) memset(&context->blit_targets[1], 0, clear_size);
509 context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location);
511 else
513 context_apply_fbo_state(context, target, NULL, NULL, location);
517 /* Context activation is done by the caller. */
518 void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
520 const struct wined3d_gl_info *gl_info = context->gl_info;
522 if (context->free_occlusion_query_count)
524 query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
526 else
528 if (gl_info->supported[ARB_OCCLUSION_QUERY])
530 ENTER_GL();
531 GL_EXTCALL(glGenQueriesARB(1, &query->id));
532 checkGLcall("glGenQueriesARB");
533 LEAVE_GL();
535 TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
537 else
539 WARN("Occlusion queries not supported, not allocating query id.\n");
540 query->id = 0;
544 query->context = context;
545 list_add_head(&context->occlusion_queries, &query->entry);
548 void context_free_occlusion_query(struct wined3d_occlusion_query *query)
550 struct wined3d_context *context = query->context;
552 list_remove(&query->entry);
553 query->context = NULL;
555 if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
557 UINT new_size = context->free_occlusion_query_size << 1;
558 GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
559 new_size * sizeof(*context->free_occlusion_queries));
561 if (!new_data)
563 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
564 return;
567 context->free_occlusion_query_size = new_size;
568 context->free_occlusion_queries = new_data;
571 context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
574 /* Context activation is done by the caller. */
575 void context_alloc_event_query(struct wined3d_context *context, struct wined3d_event_query *query)
577 const struct wined3d_gl_info *gl_info = context->gl_info;
579 if (context->free_event_query_count)
581 query->object = context->free_event_queries[--context->free_event_query_count];
583 else
585 if (gl_info->supported[ARB_SYNC])
587 /* Using ARB_sync, not much to do here. */
588 query->object.sync = NULL;
589 TRACE("Allocated event query %p in context %p.\n", query->object.sync, context);
591 else if (gl_info->supported[APPLE_FENCE])
593 ENTER_GL();
594 GL_EXTCALL(glGenFencesAPPLE(1, &query->object.id));
595 checkGLcall("glGenFencesAPPLE");
596 LEAVE_GL();
598 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
600 else if(gl_info->supported[NV_FENCE])
602 ENTER_GL();
603 GL_EXTCALL(glGenFencesNV(1, &query->object.id));
604 checkGLcall("glGenFencesNV");
605 LEAVE_GL();
607 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
609 else
611 WARN("Event queries not supported, not allocating query id.\n");
612 query->object.id = 0;
616 query->context = context;
617 list_add_head(&context->event_queries, &query->entry);
620 void context_free_event_query(struct wined3d_event_query *query)
622 struct wined3d_context *context = query->context;
624 list_remove(&query->entry);
625 query->context = NULL;
627 if (context->free_event_query_count >= context->free_event_query_size - 1)
629 UINT new_size = context->free_event_query_size << 1;
630 union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
631 new_size * sizeof(*context->free_event_queries));
633 if (!new_data)
635 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->object.id, context);
636 return;
639 context->free_event_query_size = new_size;
640 context->free_event_queries = new_data;
643 context->free_event_queries[context->free_event_query_count++] = query->object;
646 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
648 static void context_enum_surface_fbo_entries(IWineD3DDeviceImpl *device,
649 IWineD3DSurfaceImpl *surface, context_fbo_entry_func_t *callback)
651 UINT i;
653 for (i = 0; i < device->numContexts; ++i)
655 struct wined3d_context *context = device->contexts[i];
656 const struct wined3d_gl_info *gl_info = context->gl_info;
657 struct fbo_entry *entry, *entry2;
659 if (context->current_rt == surface) context->current_rt = NULL;
661 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
663 UINT j;
665 if (entry->depth_stencil == surface)
667 callback(context, entry);
668 continue;
671 for (j = 0; j < gl_info->limits.buffers; ++j)
673 if (entry->render_targets[j] == surface)
675 callback(context, entry);
676 break;
683 static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
685 list_remove(&entry->entry);
686 list_add_head(&context->fbo_destroy_list, &entry->entry);
689 void context_resource_released(struct IWineD3DDeviceImpl *device,
690 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
692 if (!device->d3d_initialized) return;
694 switch (type)
696 case WINED3DRTYPE_SURFACE:
697 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
698 context_queue_fbo_entry_destruction);
699 break;
701 default:
702 break;
706 static void context_detach_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
708 entry->attached = FALSE;
711 void context_resource_unloaded(struct IWineD3DDeviceImpl *device,
712 struct wined3d_resource *resource, WINED3DRESOURCETYPE type)
714 switch (type)
716 case WINED3DRTYPE_SURFACE:
717 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
718 context_detach_fbo_entry);
719 break;
721 default:
722 break;
726 void context_surface_update(struct wined3d_context *context, IWineD3DSurfaceImpl *surface)
728 const struct wined3d_gl_info *gl_info = context->gl_info;
729 struct fbo_entry *entry = context->current_fbo;
730 unsigned int i;
732 if (!entry || context->rebind_fbo) return;
734 for (i = 0; i < gl_info->limits.buffers; ++i)
736 if (surface == entry->render_targets[i])
738 TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
739 context->rebind_fbo = TRUE;
740 return;
744 if (surface == entry->depth_stencil)
746 TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
747 context->rebind_fbo = TRUE;
751 static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
753 int current = GetPixelFormat(dc);
755 if (current == format) return TRUE;
757 if (!current)
759 if (!SetPixelFormat(dc, format, NULL))
761 ERR("Failed to set pixel format %d on device context %p, last error %#x.\n",
762 format, dc, GetLastError());
763 return FALSE;
765 return TRUE;
768 /* By default WGL doesn't allow pixel format adjustments but we need it
769 * here. For this reason there's a Wine specific wglSetPixelFormat()
770 * which allows us to set the pixel format multiple times. Only use it
771 * when really needed. */
772 if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
774 if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format, NULL)))
776 ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
777 format, dc);
778 return FALSE;
780 return TRUE;
783 /* OpenGL doesn't allow pixel format adjustments. Print an error and
784 * continue using the old format. There's a big chance that the old
785 * format works although with a performance hit and perhaps rendering
786 * errors. */
787 ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
788 format, dc, current);
789 return TRUE;
792 static void context_update_window(struct wined3d_context *context)
794 TRACE("Updating context %p window from %p to %p.\n",
795 context, context->win_handle, context->swapchain->win_handle);
797 if (context->valid)
799 if (!ReleaseDC(context->win_handle, context->hdc))
801 ERR("Failed to release device context %p, last error %#x.\n",
802 context->hdc, GetLastError());
805 else context->valid = 1;
807 context->win_handle = context->swapchain->win_handle;
809 if (!(context->hdc = GetDC(context->win_handle)))
811 ERR("Failed to get a device context for window %p.\n", context->win_handle);
812 goto err;
815 if (!context_set_pixel_format(context->gl_info, context->hdc, context->pixel_format))
817 ERR("Failed to set pixel format %d on device context %p.\n",
818 context->pixel_format, context->hdc);
819 goto err;
822 if (!pwglMakeCurrent(context->hdc, context->glCtx))
824 ERR("Failed to make GL context %p current on device context %p, last error %#x.\n",
825 context->glCtx, context->hdc, GetLastError());
826 goto err;
829 return;
831 err:
832 context->valid = 0;
835 /* Do not call while under the GL lock. */
836 static void context_validate(struct wined3d_context *context)
838 HWND wnd = WindowFromDC(context->hdc);
840 if (wnd != context->win_handle)
842 WARN("DC %p belongs to window %p instead of %p.\n",
843 context->hdc, wnd, context->win_handle);
844 context->valid = 0;
847 if (context->win_handle != context->swapchain->win_handle)
848 context_update_window(context);
851 /* Do not call while under the GL lock. */
852 static void context_destroy_gl_resources(struct wined3d_context *context)
854 const struct wined3d_gl_info *gl_info = context->gl_info;
855 struct wined3d_occlusion_query *occlusion_query;
856 struct wined3d_event_query *event_query;
857 struct fbo_entry *entry, *entry2;
858 HGLRC restore_ctx;
859 HDC restore_dc;
860 unsigned int i;
862 restore_ctx = pwglGetCurrentContext();
863 restore_dc = pwglGetCurrentDC();
865 context_validate(context);
866 if (context->valid && restore_ctx != context->glCtx) pwglMakeCurrent(context->hdc, context->glCtx);
867 else restore_ctx = NULL;
869 ENTER_GL();
871 LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
873 if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
874 GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
875 occlusion_query->context = NULL;
878 LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
880 if (context->valid)
882 if (gl_info->supported[ARB_SYNC])
884 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
886 else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
887 else if (gl_info->supported[NV_FENCE]) GL_EXTCALL(glDeleteFencesNV(1, &event_query->object.id));
889 event_query->context = NULL;
892 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
894 if (!context->valid) entry->id = 0;
895 context_destroy_fbo_entry(context, entry);
898 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
900 if (!context->valid) entry->id = 0;
901 context_destroy_fbo_entry(context, entry);
904 if (context->valid)
906 if (context->dst_fbo)
908 TRACE("Destroy dst FBO %d\n", context->dst_fbo);
909 context_destroy_fbo(context, &context->dst_fbo);
911 if (context->dummy_arbfp_prog)
913 GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
916 if (gl_info->supported[ARB_OCCLUSION_QUERY])
917 GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
919 if (gl_info->supported[ARB_SYNC])
921 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
923 else if (gl_info->supported[APPLE_FENCE])
925 for (i = 0; i < context->free_event_query_count; ++i)
927 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_event_queries[i].id));
930 else if (gl_info->supported[NV_FENCE])
932 for (i = 0; i < context->free_event_query_count; ++i)
934 GL_EXTCALL(glDeleteFencesNV(1, &context->free_event_queries[i].id));
938 checkGLcall("context cleanup");
941 LEAVE_GL();
943 HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
944 HeapFree(GetProcessHeap(), 0, context->free_event_queries);
946 if (restore_ctx)
948 if (!pwglMakeCurrent(restore_dc, restore_ctx))
950 DWORD err = GetLastError();
951 ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
952 restore_ctx, restore_dc, err);
955 else if (pwglGetCurrentContext() && !pwglMakeCurrent(NULL, NULL))
957 ERR("Failed to disable GL context.\n");
960 ReleaseDC(context->win_handle, context->hdc);
962 if (!pwglDeleteContext(context->glCtx))
964 DWORD err = GetLastError();
965 ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
969 DWORD context_get_tls_idx(void)
971 return wined3d_context_tls_idx;
974 void context_set_tls_idx(DWORD idx)
976 wined3d_context_tls_idx = idx;
979 struct wined3d_context *context_get_current(void)
981 return TlsGetValue(wined3d_context_tls_idx);
984 /* Do not call while under the GL lock. */
985 BOOL context_set_current(struct wined3d_context *ctx)
987 struct wined3d_context *old = context_get_current();
989 if (old == ctx)
991 TRACE("Already using D3D context %p.\n", ctx);
992 return TRUE;
995 if (old)
997 if (old->destroyed)
999 TRACE("Switching away from destroyed context %p.\n", old);
1000 context_destroy_gl_resources(old);
1001 HeapFree(GetProcessHeap(), 0, old);
1003 else
1005 old->current = 0;
1009 if (ctx)
1011 TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
1012 if (!pwglMakeCurrent(ctx->hdc, ctx->glCtx))
1014 DWORD err = GetLastError();
1015 ERR("Failed to make GL context %p current on device context %p, last error %#x.\n",
1016 ctx->glCtx, ctx->hdc, err);
1017 TlsSetValue(wined3d_context_tls_idx, NULL);
1018 return FALSE;
1020 ctx->current = 1;
1022 else if(pwglGetCurrentContext())
1024 TRACE("Clearing current D3D context.\n");
1025 if (!pwglMakeCurrent(NULL, NULL))
1027 DWORD err = GetLastError();
1028 ERR("Failed to clear current GL context, last error %#x.\n", err);
1029 TlsSetValue(wined3d_context_tls_idx, NULL);
1030 return FALSE;
1034 return TlsSetValue(wined3d_context_tls_idx, ctx);
1037 void context_release(struct wined3d_context *context)
1039 TRACE("Releasing context %p, level %u.\n", context, context->level);
1041 if (WARN_ON(d3d))
1043 if (!context->level)
1044 WARN("Context %p is not active.\n", context);
1045 else if (context != context_get_current())
1046 WARN("Context %p is not the current context.\n", context);
1049 if (!--context->level && context->restore_ctx)
1051 TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1052 if (!pwglMakeCurrent(context->restore_dc, context->restore_ctx))
1054 DWORD err = GetLastError();
1055 ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
1056 context->restore_ctx, context->restore_dc, err);
1058 context->restore_ctx = NULL;
1059 context->restore_dc = NULL;
1063 static void context_enter(struct wined3d_context *context)
1065 TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1067 if (!context->level++)
1069 const struct wined3d_context *current_context = context_get_current();
1070 HGLRC current_gl = pwglGetCurrentContext();
1072 if (current_gl && (!current_context || current_context->glCtx != current_gl))
1074 TRACE("Another GL context (%p on device context %p) is already current.\n",
1075 current_gl, pwglGetCurrentDC());
1076 context->restore_ctx = current_gl;
1077 context->restore_dc = pwglGetCurrentDC();
1082 /*****************************************************************************
1083 * Context_MarkStateDirty
1085 * Marks a state in a context dirty. Only one context, opposed to
1086 * IWineD3DDeviceImpl_MarkStateDirty, which marks the state dirty in all
1087 * contexts
1089 * Params:
1090 * context: Context to mark the state dirty in
1091 * state: State to mark dirty
1092 * StateTable: Pointer to the state table in use(for state grouping)
1094 *****************************************************************************/
1095 static void Context_MarkStateDirty(struct wined3d_context *context, DWORD state, const struct StateEntry *StateTable)
1097 DWORD rep = StateTable[state].representative;
1098 DWORD idx;
1099 BYTE shift;
1101 if (isStateDirty(context, rep)) return;
1103 context->dirtyArray[context->numDirtyEntries++] = rep;
1104 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1105 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1106 context->isStateDirty[idx] |= (1 << shift);
1109 /* This function takes care of WineD3D pixel format selection. */
1110 static int WineD3D_ChoosePixelFormat(IWineD3DDeviceImpl *This, HDC hdc,
1111 const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1112 BOOL auxBuffers, int numSamples, BOOL findCompatible)
1114 int iPixelFormat=0;
1115 unsigned int matchtry;
1116 short redBits, greenBits, blueBits, alphaBits, colorBits;
1117 short depthBits=0, stencilBits=0;
1119 static const struct
1121 BOOL require_aux;
1122 BOOL exact_alpha;
1123 BOOL exact_color;
1125 matches[] =
1127 /* First, try without alpha match buffers. MacOS supports aux buffers only
1128 * on A8R8G8B8, and we prefer better offscreen rendering over an alpha match.
1129 * Then try without aux buffers - this is the most common cause for not
1130 * finding a pixel format. Also some drivers(the open source ones)
1131 * only offer 32 bit ARB pixel formats. First try without an exact alpha
1132 * match, then try without an exact alpha and color match.
1134 { TRUE, TRUE, TRUE },
1135 { TRUE, FALSE, TRUE },
1136 { FALSE, TRUE, TRUE },
1137 { FALSE, FALSE, TRUE },
1138 { TRUE, FALSE, FALSE },
1139 { FALSE, FALSE, FALSE },
1142 int i = 0;
1143 int nCfgs = This->adapter->nCfgs;
1145 TRACE("ColorFormat=%s, DepthStencilFormat=%s, auxBuffers=%d, numSamples=%d, findCompatible=%d\n",
1146 debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1147 auxBuffers, numSamples, findCompatible);
1149 if (!getColorBits(color_format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits))
1151 ERR("Unable to get color bits for format %s (%#x)!\n",
1152 debug_d3dformat(color_format->id), color_format->id);
1153 return 0;
1156 getDepthStencilBits(ds_format, &depthBits, &stencilBits);
1158 for(matchtry = 0; matchtry < (sizeof(matches) / sizeof(matches[0])) && !iPixelFormat; matchtry++) {
1159 for(i=0; i<nCfgs; i++) {
1160 BOOL exactDepthMatch = TRUE;
1161 WineD3D_PixelFormat *cfg = &This->adapter->cfgs[i];
1163 /* For now only accept RGBA formats. Perhaps some day we will
1164 * allow floating point formats for pbuffers. */
1165 if(cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1166 continue;
1168 /* In window mode we need a window drawable format and double buffering. */
1169 if(!(cfg->windowDrawable && cfg->doubleBuffer))
1170 continue;
1172 /* We like to have aux buffers in backbuffer mode */
1173 if(auxBuffers && !cfg->auxBuffers && matches[matchtry].require_aux)
1174 continue;
1176 if(matches[matchtry].exact_color) {
1177 if(cfg->redSize != redBits)
1178 continue;
1179 if(cfg->greenSize != greenBits)
1180 continue;
1181 if(cfg->blueSize != blueBits)
1182 continue;
1183 } else {
1184 if(cfg->redSize < redBits)
1185 continue;
1186 if(cfg->greenSize < greenBits)
1187 continue;
1188 if(cfg->blueSize < blueBits)
1189 continue;
1191 if(matches[matchtry].exact_alpha) {
1192 if(cfg->alphaSize != alphaBits)
1193 continue;
1194 } else {
1195 if(cfg->alphaSize < alphaBits)
1196 continue;
1199 /* We try to locate a format which matches our requirements exactly. In case of
1200 * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1201 if(cfg->depthSize < depthBits)
1202 continue;
1203 else if(cfg->depthSize > depthBits)
1204 exactDepthMatch = FALSE;
1206 /* In all cases make sure the number of stencil bits matches our requirements
1207 * even when we don't need stencil because it could affect performance EXCEPT
1208 * on cards which don't offer depth formats without stencil like the i915 drivers
1209 * on Linux. */
1210 if(stencilBits != cfg->stencilSize && !(This->adapter->brokenStencil && stencilBits <= cfg->stencilSize))
1211 continue;
1213 /* Check multisampling support */
1214 if(cfg->numSamples != numSamples)
1215 continue;
1217 /* When we have passed all the checks then we have found a format which matches our
1218 * requirements. Note that we only check for a limit number of capabilities right now,
1219 * so there can easily be a dozen of pixel formats which appear to be the 'same' but
1220 * can still differ in things like multisampling, stereo, SRGB and other flags.
1223 /* Exit the loop as we have found a format :) */
1224 if(exactDepthMatch) {
1225 iPixelFormat = cfg->iPixelFormat;
1226 break;
1227 } else if(!iPixelFormat) {
1228 /* In the end we might end up with a format which doesn't exactly match our depth
1229 * requirements. Accept the first format we found because formats with higher iPixelFormat
1230 * values tend to have more extended capabilities (e.g. multisampling) which we don't need. */
1231 iPixelFormat = cfg->iPixelFormat;
1236 /* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
1237 if(!iPixelFormat && !findCompatible) {
1238 ERR("Can't find a suitable iPixelFormat\n");
1239 return FALSE;
1240 } else if(!iPixelFormat) {
1241 PIXELFORMATDESCRIPTOR pfd;
1243 TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
1244 /* PixelFormat selection */
1245 ZeroMemory(&pfd, sizeof(pfd));
1246 pfd.nSize = sizeof(pfd);
1247 pfd.nVersion = 1;
1248 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1249 pfd.iPixelType = PFD_TYPE_RGBA;
1250 pfd.cAlphaBits = alphaBits;
1251 pfd.cColorBits = colorBits;
1252 pfd.cDepthBits = depthBits;
1253 pfd.cStencilBits = stencilBits;
1254 pfd.iLayerType = PFD_MAIN_PLANE;
1256 iPixelFormat = ChoosePixelFormat(hdc, &pfd);
1257 if(!iPixelFormat) {
1258 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
1259 ERR("Can't find a suitable iPixelFormat\n");
1260 return FALSE;
1264 TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
1265 iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1266 return iPixelFormat;
1269 /* Do not call while under the GL lock. */
1270 struct wined3d_context *context_create(IWineD3DSwapChainImpl *swapchain,
1271 IWineD3DSurfaceImpl *target, const struct wined3d_format *ds_format)
1273 IWineD3DDeviceImpl *device = swapchain->device;
1274 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1275 const struct wined3d_format *color_format;
1276 struct wined3d_context *ret;
1277 PIXELFORMATDESCRIPTOR pfd;
1278 BOOL auxBuffers = FALSE;
1279 int numSamples = 0;
1280 int pixel_format;
1281 unsigned int s;
1282 int swap_interval;
1283 DWORD state;
1284 HGLRC ctx;
1285 HDC hdc;
1287 TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1289 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1290 if (!ret)
1292 ERR("Failed to allocate context memory.\n");
1293 return NULL;
1296 if (!(hdc = GetDC(swapchain->win_handle)))
1298 ERR("Failed to retrieve a device context.\n");
1299 goto out;
1302 color_format = target->resource.format;
1304 /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
1305 * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
1306 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
1308 auxBuffers = TRUE;
1310 if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
1311 color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM);
1312 else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
1313 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1316 /* DirectDraw supports 8bit paletted render targets and these are used by
1317 * old games like Starcraft and C&C. Most modern hardware doesn't support
1318 * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
1319 * conversion (ab)uses the alpha component for storing the palette index.
1320 * For this reason we require a format with 8bit alpha, so request
1321 * A8R8G8B8. */
1322 if (color_format->id == WINED3DFMT_P8_UINT)
1323 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1325 /* D3D only allows multisampling when SwapEffect is set to WINED3DSWAPEFFECT_DISCARD. */
1326 if (swapchain->presentParms.MultiSampleType && (swapchain->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD))
1328 if (!gl_info->supported[ARB_MULTISAMPLE])
1329 WARN("The application is requesting multisampling without support.\n");
1330 else
1332 TRACE("Requesting multisample type %#x.\n", swapchain->presentParms.MultiSampleType);
1333 numSamples = swapchain->presentParms.MultiSampleType;
1337 /* Try to find a pixel format which matches our requirements. */
1338 pixel_format = WineD3D_ChoosePixelFormat(device, hdc, color_format, ds_format,
1339 auxBuffers, numSamples, FALSE /* findCompatible */);
1341 /* Try to locate a compatible format if we weren't able to find anything. */
1342 if (!pixel_format)
1344 TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
1345 pixel_format = WineD3D_ChoosePixelFormat(device, hdc, color_format, ds_format,
1346 auxBuffers, 0 /* numSamples */, TRUE /* findCompatible */);
1349 /* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
1350 if (!pixel_format)
1352 ERR("Can't find a suitable pixel format.\n");
1353 goto out;
1356 DescribePixelFormat(hdc, pixel_format, sizeof(pfd), &pfd);
1357 if (!context_set_pixel_format(gl_info, hdc, pixel_format))
1359 ERR("Failed to set pixel format %d on device context %p.\n", pixel_format, hdc);
1360 goto out;
1363 ctx = pwglCreateContext(hdc);
1364 if (device->numContexts)
1366 if (!pwglShareLists(device->contexts[0]->glCtx, ctx))
1368 DWORD err = GetLastError();
1369 ERR("wglShareLists(%p, %p) failed, last error %#x.\n",
1370 device->contexts[0]->glCtx, ctx, err);
1374 if(!ctx) {
1375 ERR("Failed to create a WGL context\n");
1376 goto out;
1379 if (!device_context_add(device, ret))
1381 ERR("Failed to add the newly created context to the context list\n");
1382 if (!pwglDeleteContext(ctx))
1384 DWORD err = GetLastError();
1385 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, err);
1387 goto out;
1390 ret->gl_info = gl_info;
1392 /* Mark all states dirty to force a proper initialization of the states
1393 * on the first use of the context. */
1394 for (state = 0; state <= STATE_HIGHEST; ++state)
1396 if (device->StateTable[state].representative)
1397 Context_MarkStateDirty(ret, state, device->StateTable);
1400 ret->swapchain = swapchain;
1401 ret->current_rt = target;
1402 ret->tid = GetCurrentThreadId();
1404 ret->render_offscreen = surface_is_offscreen(target);
1405 ret->draw_buffer_dirty = TRUE;
1406 ret->valid = 1;
1408 ret->glCtx = ctx;
1409 ret->win_handle = swapchain->win_handle;
1410 ret->hdc = hdc;
1411 ret->pixel_format = pixel_format;
1413 if (device->shader_backend->shader_dirtifyable_constants())
1415 /* Create the dirty constants array and initialize them to dirty */
1416 ret->vshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1417 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1418 ret->pshader_const_dirty = HeapAlloc(GetProcessHeap(), 0,
1419 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1420 memset(ret->vshader_const_dirty, 1,
1421 sizeof(*ret->vshader_const_dirty) * device->d3d_vshader_constantF);
1422 memset(ret->pshader_const_dirty, 1,
1423 sizeof(*ret->pshader_const_dirty) * device->d3d_pshader_constantF);
1426 ret->blit_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1427 gl_info->limits.buffers * sizeof(*ret->blit_targets));
1428 if (!ret->blit_targets) goto out;
1430 ret->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1431 gl_info->limits.buffers * sizeof(*ret->draw_buffers));
1432 if (!ret->draw_buffers) goto out;
1434 ret->free_occlusion_query_size = 4;
1435 ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
1436 ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
1437 if (!ret->free_occlusion_queries) goto out;
1439 list_init(&ret->occlusion_queries);
1441 ret->free_event_query_size = 4;
1442 ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
1443 ret->free_event_query_size * sizeof(*ret->free_event_queries));
1444 if (!ret->free_event_queries) goto out;
1446 list_init(&ret->event_queries);
1448 TRACE("Successfully created new context %p\n", ret);
1450 list_init(&ret->fbo_list);
1451 list_init(&ret->fbo_destroy_list);
1453 context_enter(ret);
1455 /* Set up the context defaults */
1456 if (!context_set_current(ret))
1458 ERR("Cannot activate context to set up defaults\n");
1459 context_release(ret);
1460 goto out;
1463 switch (swapchain->presentParms.PresentationInterval)
1465 case WINED3DPRESENT_INTERVAL_IMMEDIATE:
1466 swap_interval = 0;
1467 break;
1468 case WINED3DPRESENT_INTERVAL_DEFAULT:
1469 case WINED3DPRESENT_INTERVAL_ONE:
1470 swap_interval = 1;
1471 break;
1472 case WINED3DPRESENT_INTERVAL_TWO:
1473 swap_interval = 2;
1474 break;
1475 case WINED3DPRESENT_INTERVAL_THREE:
1476 swap_interval = 3;
1477 break;
1478 case WINED3DPRESENT_INTERVAL_FOUR:
1479 swap_interval = 4;
1480 break;
1481 default:
1482 FIXME("Unknown presentation interval %08x\n", swapchain->presentParms.PresentationInterval);
1483 swap_interval = 1;
1486 if (gl_info->supported[WGL_EXT_SWAP_CONTROL])
1488 if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
1489 ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
1490 swap_interval, ret, GetLastError());
1493 ENTER_GL();
1495 glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
1497 TRACE("Setting up the screen\n");
1498 /* Clear the screen */
1499 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
1500 checkGLcall("glClearColor");
1501 glClearIndex(0);
1502 glClearDepth(1);
1503 glClearStencil(0xffff);
1505 checkGLcall("glClear");
1507 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1508 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1510 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1511 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1513 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1514 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1516 glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
1517 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
1518 glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);
1519 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
1521 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1523 /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
1524 * and textures in DIB sections(due to the memory protection).
1526 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1527 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1529 if (gl_info->supported[ARB_VERTEX_BLEND])
1531 /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one
1532 * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless
1533 * GL_VERTEX_BLEND_ARB isn't enabled too
1535 glEnable(GL_WEIGHT_SUM_UNITY_ARB);
1536 checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
1538 if (gl_info->supported[NV_TEXTURE_SHADER2])
1540 /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
1541 * the previous texture where to source the offset from is always unit - 1.
1543 for (s = 1; s < gl_info->limits.textures; ++s)
1545 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
1546 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
1547 checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
1550 if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
1552 /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
1553 * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
1554 * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
1555 * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
1556 * is ever assigned.
1558 * So make sure a program is assigned to each context. The first real ARBFP use will set a different
1559 * program and the dummy program is destroyed when the context is destroyed.
1561 const char *dummy_program =
1562 "!!ARBfp1.0\n"
1563 "MOV result.color, fragment.color.primary;\n"
1564 "END\n";
1565 GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
1566 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
1567 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
1570 for (s = 0; s < gl_info->limits.point_sprite_units; ++s)
1572 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
1573 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
1574 checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
1577 if (gl_info->supported[ARB_PROVOKING_VERTEX])
1579 GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
1581 else if (gl_info->supported[EXT_PROVOKING_VERTEX])
1583 GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
1586 LEAVE_GL();
1588 device->frag_pipe->enable_extension(TRUE);
1590 TRACE("Created context %p.\n", ret);
1592 return ret;
1594 out:
1595 HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
1596 HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
1597 HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
1598 HeapFree(GetProcessHeap(), 0, ret->blit_targets);
1599 HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
1600 HeapFree(GetProcessHeap(), 0, ret->vshader_const_dirty);
1601 HeapFree(GetProcessHeap(), 0, ret);
1602 return NULL;
1605 /* Do not call while under the GL lock. */
1606 void context_destroy(IWineD3DDeviceImpl *This, struct wined3d_context *context)
1608 BOOL destroy;
1610 TRACE("Destroying ctx %p\n", context);
1612 if (context->tid == GetCurrentThreadId() || !context->current)
1614 context_destroy_gl_resources(context);
1615 TlsSetValue(wined3d_context_tls_idx, NULL);
1616 destroy = TRUE;
1618 else
1620 context->destroyed = 1;
1621 destroy = FALSE;
1624 HeapFree(GetProcessHeap(), 0, context->draw_buffers);
1625 HeapFree(GetProcessHeap(), 0, context->blit_targets);
1626 HeapFree(GetProcessHeap(), 0, context->vshader_const_dirty);
1627 HeapFree(GetProcessHeap(), 0, context->pshader_const_dirty);
1628 device_context_remove(This, context);
1629 if (destroy) HeapFree(GetProcessHeap(), 0, context);
1632 /* GL locking is done by the caller */
1633 static inline void set_blit_dimension(UINT width, UINT height) {
1634 glMatrixMode(GL_PROJECTION);
1635 checkGLcall("glMatrixMode(GL_PROJECTION)");
1636 glLoadIdentity();
1637 checkGLcall("glLoadIdentity()");
1638 glOrtho(0, width, 0, height, 0.0, -1.0);
1639 checkGLcall("glOrtho");
1640 glViewport(0, 0, width, height);
1641 checkGLcall("glViewport");
1644 /*****************************************************************************
1645 * SetupForBlit
1647 * Sets up a context for DirectDraw blitting.
1648 * All texture units are disabled, texture unit 0 is set as current unit
1649 * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
1650 * color writing enabled for all channels
1651 * register combiners disabled, shaders disabled
1652 * world matrix is set to identity, texture matrix 0 too
1653 * projection matrix is setup for drawing screen coordinates
1655 * Params:
1656 * This: Device to activate the context for
1657 * context: Context to setup
1659 *****************************************************************************/
1660 /* Context activation is done by the caller. */
1661 static void SetupForBlit(IWineD3DDeviceImpl *This, struct wined3d_context *context)
1663 int i;
1664 const struct StateEntry *StateTable = This->StateTable;
1665 const struct wined3d_gl_info *gl_info = context->gl_info;
1666 UINT width = context->current_rt->resource.width;
1667 UINT height = context->current_rt->resource.height;
1668 DWORD sampler;
1670 TRACE("Setting up context %p for blitting\n", context);
1671 if(context->last_was_blit) {
1672 if(context->blit_w != width || context->blit_h != height) {
1673 ENTER_GL();
1674 set_blit_dimension(width, height);
1675 LEAVE_GL();
1676 context->blit_w = width; context->blit_h = height;
1677 /* No need to dirtify here, the states are still dirtified because they weren't
1678 * applied since the last SetupForBlit call. Otherwise last_was_blit would not
1679 * be set
1682 TRACE("Context is already set up for blitting, nothing to do\n");
1683 return;
1685 context->last_was_blit = TRUE;
1687 /* TODO: Use a display list */
1689 /* Disable shaders */
1690 ENTER_GL();
1691 This->shader_backend->shader_select(context, FALSE, FALSE);
1692 LEAVE_GL();
1694 Context_MarkStateDirty(context, STATE_VSHADER, StateTable);
1695 Context_MarkStateDirty(context, STATE_PIXELSHADER, StateTable);
1697 /* Call ENTER_GL() once for all gl calls below. In theory we should not call
1698 * helper functions in between gl calls. This function is full of Context_MarkStateDirty
1699 * which can safely be called from here, we only lock once instead locking/unlocking
1700 * after each GL call.
1702 ENTER_GL();
1704 /* Disable all textures. The caller can then bind a texture it wants to blit
1705 * from
1707 * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
1708 * function texture unit. No need to care for higher samplers
1710 for (i = gl_info->limits.textures - 1; i > 0 ; --i)
1712 sampler = This->rev_tex_unit_map[i];
1713 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1714 checkGLcall("glActiveTextureARB");
1716 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1718 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1719 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1721 glDisable(GL_TEXTURE_3D);
1722 checkGLcall("glDisable GL_TEXTURE_3D");
1723 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1725 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1726 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1728 glDisable(GL_TEXTURE_2D);
1729 checkGLcall("glDisable GL_TEXTURE_2D");
1731 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1732 checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
1734 if (sampler != WINED3D_UNMAPPED_STAGE)
1736 if (sampler < MAX_TEXTURES) {
1737 Context_MarkStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP), StateTable);
1739 Context_MarkStateDirty(context, STATE_SAMPLER(sampler), StateTable);
1742 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1743 checkGLcall("glActiveTextureARB");
1745 sampler = This->rev_tex_unit_map[0];
1747 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1749 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1750 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
1752 glDisable(GL_TEXTURE_3D);
1753 checkGLcall("glDisable GL_TEXTURE_3D");
1754 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1756 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1757 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
1759 glDisable(GL_TEXTURE_2D);
1760 checkGLcall("glDisable GL_TEXTURE_2D");
1762 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1764 glMatrixMode(GL_TEXTURE);
1765 checkGLcall("glMatrixMode(GL_TEXTURE)");
1766 glLoadIdentity();
1767 checkGLcall("glLoadIdentity()");
1769 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
1771 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
1772 GL_TEXTURE_LOD_BIAS_EXT,
1773 0.0f);
1774 checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
1777 if (sampler != WINED3D_UNMAPPED_STAGE)
1779 if (sampler < MAX_TEXTURES) {
1780 Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + sampler), StateTable);
1781 Context_MarkStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP), StateTable);
1783 Context_MarkStateDirty(context, STATE_SAMPLER(sampler), StateTable);
1786 /* Other misc states */
1787 glDisable(GL_ALPHA_TEST);
1788 checkGLcall("glDisable(GL_ALPHA_TEST)");
1789 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHATESTENABLE), StateTable);
1790 glDisable(GL_LIGHTING);
1791 checkGLcall("glDisable GL_LIGHTING");
1792 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING), StateTable);
1793 glDisable(GL_DEPTH_TEST);
1794 checkGLcall("glDisable GL_DEPTH_TEST");
1795 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ZENABLE), StateTable);
1796 glDisableWINE(GL_FOG);
1797 checkGLcall("glDisable GL_FOG");
1798 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_FOGENABLE), StateTable);
1799 glDisable(GL_BLEND);
1800 checkGLcall("glDisable GL_BLEND");
1801 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
1802 glDisable(GL_CULL_FACE);
1803 checkGLcall("glDisable GL_CULL_FACE");
1804 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CULLMODE), StateTable);
1805 glDisable(GL_STENCIL_TEST);
1806 checkGLcall("glDisable GL_STENCIL_TEST");
1807 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_STENCILENABLE), StateTable);
1808 glDisable(GL_SCISSOR_TEST);
1809 checkGLcall("glDisable GL_SCISSOR_TEST");
1810 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), StateTable);
1811 if (gl_info->supported[ARB_POINT_SPRITE])
1813 glDisable(GL_POINT_SPRITE_ARB);
1814 checkGLcall("glDisable GL_POINT_SPRITE_ARB");
1815 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_POINTSPRITEENABLE), StateTable);
1817 glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
1818 checkGLcall("glColorMask");
1819 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE), StateTable);
1820 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1), StateTable);
1821 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2), StateTable);
1822 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3), StateTable);
1823 if (gl_info->supported[EXT_SECONDARY_COLOR])
1825 glDisable(GL_COLOR_SUM_EXT);
1826 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SPECULARENABLE), StateTable);
1827 checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
1830 /* Setup transforms */
1831 glMatrixMode(GL_MODELVIEW);
1832 checkGLcall("glMatrixMode(GL_MODELVIEW)");
1833 glLoadIdentity();
1834 checkGLcall("glLoadIdentity()");
1835 Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), StateTable);
1837 context->last_was_rhw = TRUE;
1838 Context_MarkStateDirty(context, STATE_VDECL, StateTable); /* because of last_was_rhw = TRUE */
1840 glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
1841 glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
1842 glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
1843 glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
1844 glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
1845 glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
1846 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING), StateTable);
1848 set_blit_dimension(width, height);
1850 LEAVE_GL();
1852 context->blit_w = width; context->blit_h = height;
1853 Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
1854 Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
1856 This->frag_pipe->enable_extension(FALSE);
1859 /* Do not call while under the GL lock. */
1860 static struct wined3d_context *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target)
1862 struct wined3d_context *current_context = context_get_current();
1863 struct wined3d_context *context;
1865 if (current_context && current_context->destroyed) current_context = NULL;
1867 if (!target)
1869 if (current_context
1870 && current_context->current_rt
1871 && current_context->swapchain->device == This)
1873 target = current_context->current_rt;
1875 else
1877 IWineD3DSwapChainImpl *swapchain = This->swapchains[0];
1878 if (swapchain->back_buffers) target = swapchain->back_buffers[0];
1879 else target = swapchain->front_buffer;
1883 if (current_context && current_context->current_rt == target)
1885 context_validate(current_context);
1886 return current_context;
1889 if (target->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1891 TRACE("Rendering onscreen\n");
1893 context = swapchain_get_context(target->container.u.swapchain);
1895 else
1897 TRACE("Rendering offscreen\n");
1899 /* Stay with the current context if possible. Otherwise use the
1900 * context for the primary swapchain. */
1901 if (current_context && current_context->swapchain->device == This)
1902 context = current_context;
1903 else
1904 context = swapchain_get_context(This->swapchains[0]);
1907 context_validate(context);
1909 return context;
1912 /* Context activation is done by the caller. */
1913 static void context_apply_draw_buffers(struct wined3d_context *context, UINT rt_count, IWineD3DSurfaceImpl **rts)
1915 if (!surface_is_offscreen(rts[0]))
1917 ENTER_GL();
1918 glDrawBuffer(surface_get_gl_buffer(rts[0]));
1919 checkGLcall("glDrawBuffer()");
1920 LEAVE_GL();
1922 else
1924 ENTER_GL();
1925 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
1927 const struct wined3d_gl_info *gl_info = context->gl_info;
1928 unsigned int i;
1930 for (i = 0; i < gl_info->limits.buffers; ++i)
1932 if (i < rt_count && rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
1933 context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
1934 else
1935 context->draw_buffers[i] = GL_NONE;
1938 if (gl_info->supported[ARB_DRAW_BUFFERS])
1940 GL_EXTCALL(glDrawBuffersARB(gl_info->limits.buffers, context->draw_buffers));
1941 checkGLcall("glDrawBuffers()");
1943 else
1945 glDrawBuffer(context->draw_buffers[0]);
1946 checkGLcall("glDrawBuffer()");
1949 else
1951 glDrawBuffer(rts[0]->resource.device->offscreenBuffer);
1952 checkGLcall("glDrawBuffer()");
1954 LEAVE_GL();
1958 /* GL locking is done by the caller. */
1959 void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
1961 glDrawBuffer(buffer);
1962 checkGLcall("glDrawBuffer()");
1963 context->draw_buffer_dirty = TRUE;
1966 static inline void context_set_render_offscreen(struct wined3d_context *context, const struct StateEntry *StateTable,
1967 BOOL offscreen)
1969 if (context->render_offscreen == offscreen) return;
1971 Context_MarkStateDirty(context, STATE_POINTSPRITECOORDORIGIN, StateTable);
1972 Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
1973 Context_MarkStateDirty(context, STATE_VDECL, StateTable);
1974 Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
1975 Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
1976 Context_MarkStateDirty(context, STATE_FRONTFACE, StateTable);
1977 context->render_offscreen = offscreen;
1980 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
1981 const struct wined3d_format *required)
1983 short existing_depth, existing_stencil, required_depth, required_stencil;
1985 if (existing == required) return TRUE;
1986 if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
1988 getDepthStencilBits(existing, &existing_depth, &existing_stencil);
1989 getDepthStencilBits(required, &required_depth, &required_stencil);
1991 if(existing_depth < required_depth) return FALSE;
1992 /* If stencil bits are used the exact amount is required - otherwise wrapping
1993 * won't work correctly */
1994 if(required_stencil && required_stencil != existing_stencil) return FALSE;
1995 return TRUE;
1997 /* The caller provides a context */
1998 static void context_validate_onscreen_formats(IWineD3DDeviceImpl *device,
1999 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
2001 /* Onscreen surfaces are always in a swapchain */
2002 IWineD3DSwapChainImpl *swapchain = context->current_rt->container.u.swapchain;
2004 if (context->render_offscreen || !depth_stencil) return;
2005 if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format)) return;
2007 /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
2008 * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
2009 * format. */
2010 WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2012 /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2013 surface_load_location(context->current_rt, SFLAG_INTEXTURE, NULL);
2014 swapchain->render_to_fbo = TRUE;
2015 context_set_render_offscreen(context, device->StateTable, TRUE);
2018 /* Context activation is done by the caller. */
2019 void context_apply_blit_state(struct wined3d_context *context, IWineD3DDeviceImpl *device)
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();
2033 else
2035 ENTER_GL();
2036 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
2037 LEAVE_GL();
2040 context->draw_buffer_dirty = TRUE;
2043 if (context->draw_buffer_dirty)
2045 context_apply_draw_buffers(context, 1, &context->current_rt);
2046 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
2047 context->draw_buffer_dirty = FALSE;
2050 SetupForBlit(device, context);
2053 static BOOL context_validate_rt_config(UINT rt_count,
2054 IWineD3DSurfaceImpl **rts, IWineD3DSurfaceImpl *ds)
2056 unsigned int i;
2058 if (ds) return TRUE;
2060 for (i = 0; i < rt_count; ++i)
2062 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2063 return TRUE;
2066 WARN("Invalid render target config, need at least one attachment.\n");
2067 return FALSE;
2070 /* Context activation is done by the caller. */
2071 BOOL context_apply_clear_state(struct wined3d_context *context, IWineD3DDeviceImpl *device,
2072 UINT rt_count, IWineD3DSurfaceImpl **rts, IWineD3DSurfaceImpl *depth_stencil)
2074 const struct StateEntry *state_table = device->StateTable;
2075 UINT i;
2077 if (!context_validate_rt_config(rt_count, rts, depth_stencil))
2078 return FALSE;
2081 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2083 context_validate_onscreen_formats(device, context, depth_stencil);
2085 ENTER_GL();
2087 if (surface_is_offscreen(rts[0]))
2089 for (i = 0; i < rt_count; ++i)
2091 context->blit_targets[i] = rts[i];
2093 while (i < context->gl_info->limits.buffers)
2095 context->blit_targets[i] = NULL;
2096 ++i;
2098 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE);
2100 else
2102 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2105 LEAVE_GL();
2108 context_apply_draw_buffers(context, rt_count, rts);
2109 context->draw_buffer_dirty = TRUE;
2111 if (context->last_was_blit)
2113 device->frag_pipe->enable_extension(TRUE);
2116 /* Blending and clearing should be orthogonal, but tests on the nvidia
2117 * driver show that disabling blending when clearing improves the clearing
2118 * performance incredibly. */
2119 ENTER_GL();
2120 glDisable(GL_BLEND);
2121 glEnable(GL_SCISSOR_TEST);
2122 checkGLcall("glEnable GL_SCISSOR_TEST");
2123 LEAVE_GL();
2125 context->last_was_blit = FALSE;
2126 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_table);
2127 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), state_table);
2128 Context_MarkStateDirty(context, STATE_SCISSORRECT, state_table);
2130 return TRUE;
2133 /* Context activation is done by the caller. */
2134 BOOL context_apply_draw_state(struct wined3d_context *context, IWineD3DDeviceImpl *device)
2136 const struct StateEntry *state_table = device->StateTable;
2137 unsigned int i;
2139 if (!context_validate_rt_config(context->gl_info->limits.buffers,
2140 device->render_targets, device->depth_stencil))
2141 return FALSE;
2143 /* Preload resources before FBO setup. Texture preload in particular may
2144 * result in changes to the current FBO, due to using e.g. FBO blits for
2145 * updating a resource location. */
2146 IWineD3DDeviceImpl_FindTexUnitMap(device);
2147 device_preload_textures(device);
2148 if (isStateDirty(context, STATE_VDECL))
2149 device_update_stream_info(device, context->gl_info);
2151 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2153 context_validate_onscreen_formats(device, context, device->depth_stencil);
2155 if (!context->render_offscreen)
2157 ENTER_GL();
2158 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2159 LEAVE_GL();
2161 else
2163 ENTER_GL();
2164 context_apply_fbo_state(context, GL_FRAMEBUFFER, device->render_targets,
2165 device->depth_stencil, SFLAG_INTEXTURE);
2166 LEAVE_GL();
2170 if (context->draw_buffer_dirty)
2172 context_apply_draw_buffers(context, context->gl_info->limits.buffers, device->render_targets);
2173 context->draw_buffer_dirty = FALSE;
2176 if (context->last_was_blit)
2178 device->frag_pipe->enable_extension(TRUE);
2181 ENTER_GL();
2182 for (i = 0; i < context->numDirtyEntries; ++i)
2184 DWORD rep = context->dirtyArray[i];
2185 DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
2186 BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
2187 context->isStateDirty[idx] &= ~(1 << shift);
2188 state_table[rep].apply(rep, device->stateBlock, context);
2190 LEAVE_GL();
2191 context->numDirtyEntries = 0; /* This makes the whole list clean */
2192 context->last_was_blit = FALSE;
2194 return TRUE;
2197 static void context_setup_target(IWineD3DDeviceImpl *device,
2198 struct wined3d_context *context, IWineD3DSurfaceImpl *target)
2200 BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
2201 const struct StateEntry *StateTable = device->StateTable;
2203 if (!target) return;
2204 render_offscreen = surface_is_offscreen(target);
2205 if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
2207 /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
2208 * the alpha blend state changes with different render target formats. */
2209 if (!context->current_rt)
2211 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
2213 else
2215 const struct wined3d_format *old = context->current_rt->resource.format;
2216 const struct wined3d_format *new = target->resource.format;
2218 if (old->id != new->id)
2220 /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
2221 if ((old->alpha_mask && !new->alpha_mask) || (!old->alpha_mask && new->alpha_mask)
2222 || !(new->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
2224 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), StateTable);
2226 /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
2227 if ((old->flags & WINED3DFMT_FLAG_SRGB_WRITE) != (new->flags & WINED3DFMT_FLAG_SRGB_WRITE))
2229 Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SRGBWRITEENABLE), StateTable);
2233 /* When switching away from an offscreen render target, and we're not
2234 * using FBOs, we have to read the drawable into the texture. This is
2235 * done via PreLoad (and SFLAG_INDRAWABLE set on the surface). There
2236 * are some things that need care though. PreLoad needs a GL context,
2237 * and FindContext is called before the context is activated. It also
2238 * has to be called with the old rendertarget active, otherwise a
2239 * wrong drawable is read. */
2240 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2241 && old_render_offscreen && context->current_rt != target)
2243 /* Read the back buffer of the old drawable into the destination texture. */
2244 if (context->current_rt->texture_name_srgb)
2246 surface_internal_preload(context->current_rt, SRGB_BOTH);
2248 else
2250 surface_internal_preload(context->current_rt, SRGB_RGB);
2253 surface_modify_location(context->current_rt, SFLAG_INDRAWABLE, FALSE);
2257 context->draw_buffer_dirty = TRUE;
2258 context->current_rt = target;
2259 context_set_render_offscreen(context, StateTable, render_offscreen);
2262 /* Do not call while under the GL lock. */
2263 struct wined3d_context *context_acquire(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *target)
2265 struct wined3d_context *current_context = context_get_current();
2266 struct wined3d_context *context;
2268 TRACE("device %p, target %p.\n", device, target);
2270 context = FindContext(device, target);
2271 context_setup_target(device, context, target);
2272 context_enter(context);
2273 if (!context->valid) return context;
2275 if (context != current_context)
2277 if (!context_set_current(context)) ERR("Failed to activate the new context.\n");
2278 else device->frag_pipe->enable_extension(!context->last_was_blit);
2280 if (context->vshader_const_dirty)
2282 memset(context->vshader_const_dirty, 1,
2283 sizeof(*context->vshader_const_dirty) * device->d3d_vshader_constantF);
2284 device->highest_dirty_vs_const = device->d3d_vshader_constantF;
2286 if (context->pshader_const_dirty)
2288 memset(context->pshader_const_dirty, 1,
2289 sizeof(*context->pshader_const_dirty) * device->d3d_pshader_constantF);
2290 device->highest_dirty_ps_const = device->d3d_pshader_constantF;
2293 else if (context->restore_ctx)
2295 if (!pwglMakeCurrent(context->hdc, context->glCtx))
2297 DWORD err = GetLastError();
2298 ERR("Failed to make GL context %p current on device context %p, last error %#x.\n",
2299 context->hdc, context->glCtx, err);
2303 return context;