ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

context.c
Go to the documentation of this file.
00001 /*
00002  * Context and render target management in wined3d
00003  *
00004  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
00005  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "config.h"
00023 #include <stdio.h>
00024 #ifdef HAVE_FLOAT_H
00025 # include <float.h>
00026 #endif
00027 #include "wined3d_private.h"
00028 
00029 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
00030 
00031 static DWORD wined3d_context_tls_idx;
00032 
00033 /* FBO helper functions */
00034 
00035 /* GL locking is done by the caller */
00036 static void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint *fbo)
00037 {
00038     const struct wined3d_gl_info *gl_info = context->gl_info;
00039     GLuint f;
00040 
00041     if (!fbo)
00042     {
00043         f = 0;
00044     }
00045     else
00046     {
00047         if (!*fbo)
00048         {
00049             gl_info->fbo_ops.glGenFramebuffers(1, fbo);
00050             checkGLcall("glGenFramebuffers()");
00051             TRACE("Created FBO %u.\n", *fbo);
00052         }
00053         f = *fbo;
00054     }
00055 
00056     switch (target)
00057     {
00058         case GL_READ_FRAMEBUFFER:
00059             if (context->fbo_read_binding == f) return;
00060             context->fbo_read_binding = f;
00061             break;
00062 
00063         case GL_DRAW_FRAMEBUFFER:
00064             if (context->fbo_draw_binding == f) return;
00065             context->fbo_draw_binding = f;
00066             break;
00067 
00068         case GL_FRAMEBUFFER:
00069             if (context->fbo_read_binding == f
00070                     && context->fbo_draw_binding == f) return;
00071             context->fbo_read_binding = f;
00072             context->fbo_draw_binding = f;
00073             break;
00074 
00075         default:
00076             FIXME("Unhandled target %#x.\n", target);
00077             break;
00078     }
00079 
00080     gl_info->fbo_ops.glBindFramebuffer(target, f);
00081     checkGLcall("glBindFramebuffer()");
00082 }
00083 
00084 /* GL locking is done by the caller */
00085 static void context_clean_fbo_attachments(const struct wined3d_gl_info *gl_info, GLenum target)
00086 {
00087     unsigned int i;
00088 
00089     for (i = 0; i < gl_info->limits.buffers; ++i)
00090     {
00091         gl_info->fbo_ops.glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
00092         checkGLcall("glFramebufferTexture2D()");
00093     }
00094     gl_info->fbo_ops.glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00095     checkGLcall("glFramebufferTexture2D()");
00096 
00097     gl_info->fbo_ops.glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00098     checkGLcall("glFramebufferTexture2D()");
00099 }
00100 
00101 /* GL locking is done by the caller */
00102 static void context_destroy_fbo(struct wined3d_context *context, GLuint *fbo)
00103 {
00104     const struct wined3d_gl_info *gl_info = context->gl_info;
00105 
00106     context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
00107     context_clean_fbo_attachments(gl_info, GL_FRAMEBUFFER);
00108     context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
00109 
00110     gl_info->fbo_ops.glDeleteFramebuffers(1, fbo);
00111     checkGLcall("glDeleteFramebuffers()");
00112 }
00113 
00114 static void context_attach_depth_stencil_rb(const struct wined3d_gl_info *gl_info,
00115         GLenum fbo_target, DWORD format_flags, GLuint rb)
00116 {
00117     if (format_flags & WINED3DFMT_FLAG_DEPTH)
00118     {
00119         gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);
00120         checkGLcall("glFramebufferRenderbuffer()");
00121     }
00122 
00123     if (format_flags & WINED3DFMT_FLAG_STENCIL)
00124     {
00125         gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
00126         checkGLcall("glFramebufferRenderbuffer()");
00127     }
00128 }
00129 
00130 /* GL locking is done by the caller */
00131 static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
00132         GLenum fbo_target, struct wined3d_surface *depth_stencil, DWORD location)
00133 {
00134     const struct wined3d_gl_info *gl_info = context->gl_info;
00135 
00136     TRACE("Attach depth stencil %p\n", depth_stencil);
00137 
00138     if (depth_stencil)
00139     {
00140         DWORD format_flags = depth_stencil->resource.format->flags;
00141 
00142         if (depth_stencil->current_renderbuffer)
00143         {
00144             context_attach_depth_stencil_rb(gl_info, fbo_target,
00145                     format_flags, depth_stencil->current_renderbuffer->id);
00146         }
00147         else
00148         {
00149             switch (location)
00150             {
00151                 case SFLAG_INTEXTURE:
00152                 case SFLAG_INSRGBTEX:
00153                     surface_prepare_texture(depth_stencil, context, FALSE);
00154 
00155                     if (format_flags & WINED3DFMT_FLAG_DEPTH)
00156                     {
00157                         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
00158                                 depth_stencil->texture_target, depth_stencil->texture_name,
00159                                 depth_stencil->texture_level);
00160                         checkGLcall("glFramebufferTexture2D()");
00161                     }
00162 
00163                     if (format_flags & WINED3DFMT_FLAG_STENCIL)
00164                     {
00165                         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
00166                                 depth_stencil->texture_target, depth_stencil->texture_name,
00167                                 depth_stencil->texture_level);
00168                         checkGLcall("glFramebufferTexture2D()");
00169                     }
00170                     break;
00171 
00172                 case SFLAG_INRB_MULTISAMPLE:
00173                     surface_prepare_rb(depth_stencil, gl_info, TRUE);
00174                     context_attach_depth_stencil_rb(gl_info, fbo_target,
00175                             format_flags, depth_stencil->rb_multisample);
00176                     break;
00177 
00178                 case SFLAG_INRB_RESOLVED:
00179                     surface_prepare_rb(depth_stencil, gl_info, FALSE);
00180                     context_attach_depth_stencil_rb(gl_info, fbo_target,
00181                             format_flags, depth_stencil->rb_resolved);
00182                     break;
00183 
00184                 default:
00185                     ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
00186                     break;
00187             }
00188         }
00189 
00190         if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
00191         {
00192             gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00193             checkGLcall("glFramebufferTexture2D()");
00194         }
00195 
00196         if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
00197         {
00198             gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00199             checkGLcall("glFramebufferTexture2D()");
00200         }
00201     }
00202     else
00203     {
00204         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00205         checkGLcall("glFramebufferTexture2D()");
00206 
00207         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
00208         checkGLcall("glFramebufferTexture2D()");
00209     }
00210 }
00211 
00212 /* GL locking is done by the caller */
00213 static void context_attach_surface_fbo(struct wined3d_context *context,
00214         GLenum fbo_target, DWORD idx, struct wined3d_surface *surface, DWORD location)
00215 {
00216     const struct wined3d_gl_info *gl_info = context->gl_info;
00217 
00218     TRACE("Attach surface %p to %u\n", surface, idx);
00219 
00220     if (surface && surface->resource.format->id != WINED3DFMT_NULL)
00221     {
00222         BOOL srgb;
00223 
00224         switch (location)
00225         {
00226             case SFLAG_INTEXTURE:
00227             case SFLAG_INSRGBTEX:
00228                 srgb = location == SFLAG_INSRGBTEX;
00229                 surface_prepare_texture(surface, context, srgb);
00230                 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
00231                         surface->texture_target, surface_get_texture_name(surface, gl_info, srgb),
00232                         surface->texture_level);
00233                 checkGLcall("glFramebufferTexture2D()");
00234                 break;
00235 
00236             case SFLAG_INRB_MULTISAMPLE:
00237                 surface_prepare_rb(surface, gl_info, TRUE);
00238                 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
00239                         GL_RENDERBUFFER, surface->rb_multisample);
00240                 checkGLcall("glFramebufferRenderbuffer()");
00241                 break;
00242 
00243             case SFLAG_INRB_RESOLVED:
00244                 surface_prepare_rb(surface, gl_info, FALSE);
00245                 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
00246                         GL_RENDERBUFFER, surface->rb_resolved);
00247                 checkGLcall("glFramebufferRenderbuffer()");
00248                 break;
00249 
00250             default:
00251                 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
00252                 break;
00253         }
00254     }
00255     else
00256     {
00257         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
00258         checkGLcall("glFramebufferTexture2D()");
00259     }
00260 }
00261 
00262 /* GL locking is done by the caller */
00263 void context_check_fbo_status(const struct wined3d_context *context, GLenum target)
00264 {
00265     const struct wined3d_gl_info *gl_info = context->gl_info;
00266     GLenum status;
00267 
00268     if (!FIXME_ON(d3d)) return;
00269 
00270     status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
00271     if (status == GL_FRAMEBUFFER_COMPLETE)
00272     {
00273         TRACE("FBO complete\n");
00274     }
00275     else
00276     {
00277         const struct wined3d_surface *attachment;
00278         unsigned int i;
00279 
00280         FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
00281 
00282         if (!context->current_fbo)
00283         {
00284             ERR("FBO 0 is incomplete, driver bug?\n");
00285             return;
00286         }
00287 
00288         FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location),
00289                 context->current_fbo->location);
00290 
00291         /* Dump the FBO attachments */
00292         for (i = 0; i < gl_info->limits.buffers; ++i)
00293         {
00294             attachment = context->current_fbo->render_targets[i];
00295             if (attachment)
00296             {
00297                 FIXME("\tColor attachment %d: (%p) %s %ux%u %u samples.\n",
00298                         i, attachment, debug_d3dformat(attachment->resource.format->id),
00299                         attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
00300             }
00301         }
00302         attachment = context->current_fbo->depth_stencil;
00303         if (attachment)
00304         {
00305             FIXME("\tDepth attachment: (%p) %s %ux%u %u samples.\n",
00306                     attachment, debug_d3dformat(attachment->resource.format->id),
00307                     attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
00308         }
00309     }
00310 }
00311 
00312 static inline DWORD context_generate_rt_mask(GLenum buffer)
00313 {
00314     /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
00315     return buffer ? (1 << 31) | buffer : 0;
00316 }
00317 
00318 static inline DWORD context_generate_rt_mask_from_surface(const struct wined3d_surface *target)
00319 {
00320     return (1 << 31) | surface_get_gl_buffer(target);
00321 }
00322 
00323 static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
00324         struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
00325 {
00326     const struct wined3d_gl_info *gl_info = context->gl_info;
00327     struct fbo_entry *entry;
00328 
00329     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
00330     entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
00331     memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
00332     entry->depth_stencil = depth_stencil;
00333     entry->location = location;
00334     entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
00335     entry->attached = FALSE;
00336     entry->id = 0;
00337 
00338     return entry;
00339 }
00340 
00341 /* GL locking is done by the caller */
00342 static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
00343         struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
00344         DWORD location, struct fbo_entry *entry)
00345 {
00346     const struct wined3d_gl_info *gl_info = context->gl_info;
00347 
00348     context_bind_fbo(context, target, &entry->id);
00349     context_clean_fbo_attachments(gl_info, target);
00350 
00351     memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
00352     entry->depth_stencil = depth_stencil;
00353     entry->location = location;
00354     entry->attached = FALSE;
00355 }
00356 
00357 /* GL locking is done by the caller */
00358 static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
00359 {
00360     if (entry->id)
00361     {
00362         TRACE("Destroy FBO %d\n", entry->id);
00363         context_destroy_fbo(context, &entry->id);
00364     }
00365     --context->fbo_entry_count;
00366     list_remove(&entry->entry);
00367     HeapFree(GetProcessHeap(), 0, entry->render_targets);
00368     HeapFree(GetProcessHeap(), 0, entry);
00369 }
00370 
00371 
00372 /* GL locking is done by the caller */
00373 static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
00374         struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
00375 {
00376     const struct wined3d_gl_info *gl_info = context->gl_info;
00377     struct fbo_entry *entry;
00378 
00379     if (depth_stencil && render_targets && render_targets[0])
00380     {
00381         if (depth_stencil->resource.width < render_targets[0]->resource.width ||
00382             depth_stencil->resource.height < render_targets[0]->resource.height)
00383         {
00384             WARN("Depth stencil is smaller than the primary color buffer, disabling\n");
00385             depth_stencil = NULL;
00386         }
00387     }
00388 
00389     LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
00390     {
00391         if (!memcmp(entry->render_targets,
00392                 render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
00393                 && entry->depth_stencil == depth_stencil && entry->location == location)
00394         {
00395             list_remove(&entry->entry);
00396             list_add_head(&context->fbo_list, &entry->entry);
00397             return entry;
00398         }
00399     }
00400 
00401     if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
00402     {
00403         entry = context_create_fbo_entry(context, render_targets, depth_stencil, location);
00404         list_add_head(&context->fbo_list, &entry->entry);
00405         ++context->fbo_entry_count;
00406     }
00407     else
00408     {
00409         entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
00410         context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry);
00411         list_remove(&entry->entry);
00412         list_add_head(&context->fbo_list, &entry->entry);
00413     }
00414 
00415     return entry;
00416 }
00417 
00418 /* GL locking is done by the caller */
00419 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
00420 {
00421     const struct wined3d_gl_info *gl_info = context->gl_info;
00422     unsigned int i;
00423 
00424     context_bind_fbo(context, target, &entry->id);
00425 
00426     if (entry->attached) return;
00427 
00428     /* Apply render targets */
00429     for (i = 0; i < gl_info->limits.buffers; ++i)
00430     {
00431         context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location);
00432     }
00433 
00434     /* Apply depth targets */
00435     if (entry->depth_stencil)
00436         surface_set_compatible_renderbuffer(entry->depth_stencil, entry->render_targets[0]);
00437     context_attach_depth_stencil_fbo(context, target, entry->depth_stencil, entry->location);
00438 
00439     entry->attached = TRUE;
00440 }
00441 
00442 /* GL locking is done by the caller */
00443 static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
00444         struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
00445 {
00446     struct fbo_entry *entry, *entry2;
00447 
00448     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
00449     {
00450         context_destroy_fbo_entry(context, entry);
00451     }
00452 
00453     if (context->rebind_fbo)
00454     {
00455         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
00456         context->rebind_fbo = FALSE;
00457     }
00458 
00459     if (location == SFLAG_INDRAWABLE)
00460     {
00461         context->current_fbo = NULL;
00462         context_bind_fbo(context, target, NULL);
00463     }
00464     else
00465     {
00466         context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
00467         context_apply_fbo_entry(context, target, context->current_fbo);
00468     }
00469 }
00470 
00471 /* GL locking is done by the caller */
00472 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
00473         struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
00474 {
00475     UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets);
00476 
00477     context->blit_targets[0] = render_target;
00478     if (clear_size)
00479         memset(&context->blit_targets[1], 0, clear_size);
00480     context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location);
00481 }
00482 
00483 /* Context activation is done by the caller. */
00484 void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
00485 {
00486     const struct wined3d_gl_info *gl_info = context->gl_info;
00487 
00488     if (context->free_occlusion_query_count)
00489     {
00490         query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
00491     }
00492     else
00493     {
00494         if (gl_info->supported[ARB_OCCLUSION_QUERY])
00495         {
00496             ENTER_GL();
00497             GL_EXTCALL(glGenQueriesARB(1, &query->id));
00498             checkGLcall("glGenQueriesARB");
00499             LEAVE_GL();
00500 
00501             TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
00502         }
00503         else
00504         {
00505             WARN("Occlusion queries not supported, not allocating query id.\n");
00506             query->id = 0;
00507         }
00508     }
00509 
00510     query->context = context;
00511     list_add_head(&context->occlusion_queries, &query->entry);
00512 }
00513 
00514 void context_free_occlusion_query(struct wined3d_occlusion_query *query)
00515 {
00516     struct wined3d_context *context = query->context;
00517 
00518     list_remove(&query->entry);
00519     query->context = NULL;
00520 
00521     if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
00522     {
00523         UINT new_size = context->free_occlusion_query_size << 1;
00524         GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
00525                 new_size * sizeof(*context->free_occlusion_queries));
00526 
00527         if (!new_data)
00528         {
00529             ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
00530             return;
00531         }
00532 
00533         context->free_occlusion_query_size = new_size;
00534         context->free_occlusion_queries = new_data;
00535     }
00536 
00537     context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
00538 }
00539 
00540 /* Context activation is done by the caller. */
00541 void context_alloc_event_query(struct wined3d_context *context, struct wined3d_event_query *query)
00542 {
00543     const struct wined3d_gl_info *gl_info = context->gl_info;
00544 
00545     if (context->free_event_query_count)
00546     {
00547         query->object = context->free_event_queries[--context->free_event_query_count];
00548     }
00549     else
00550     {
00551         if (gl_info->supported[ARB_SYNC])
00552         {
00553             /* Using ARB_sync, not much to do here. */
00554             query->object.sync = NULL;
00555             TRACE("Allocated event query %p in context %p.\n", query->object.sync, context);
00556         }
00557         else if (gl_info->supported[APPLE_FENCE])
00558         {
00559             ENTER_GL();
00560             GL_EXTCALL(glGenFencesAPPLE(1, &query->object.id));
00561             checkGLcall("glGenFencesAPPLE");
00562             LEAVE_GL();
00563 
00564             TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
00565         }
00566         else if(gl_info->supported[NV_FENCE])
00567         {
00568             ENTER_GL();
00569             GL_EXTCALL(glGenFencesNV(1, &query->object.id));
00570             checkGLcall("glGenFencesNV");
00571             LEAVE_GL();
00572 
00573             TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
00574         }
00575         else
00576         {
00577             WARN("Event queries not supported, not allocating query id.\n");
00578             query->object.id = 0;
00579         }
00580     }
00581 
00582     query->context = context;
00583     list_add_head(&context->event_queries, &query->entry);
00584 }
00585 
00586 void context_free_event_query(struct wined3d_event_query *query)
00587 {
00588     struct wined3d_context *context = query->context;
00589 
00590     list_remove(&query->entry);
00591     query->context = NULL;
00592 
00593     if (context->free_event_query_count >= context->free_event_query_size - 1)
00594     {
00595         UINT new_size = context->free_event_query_size << 1;
00596         union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
00597                 new_size * sizeof(*context->free_event_queries));
00598 
00599         if (!new_data)
00600         {
00601             ERR("Failed to grow free list, leaking query %u in context %p.\n", query->object.id, context);
00602             return;
00603         }
00604 
00605         context->free_event_query_size = new_size;
00606         context->free_event_queries = new_data;
00607     }
00608 
00609     context->free_event_queries[context->free_event_query_count++] = query->object;
00610 }
00611 
00612 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
00613 
00614 static void context_enum_surface_fbo_entries(const struct wined3d_device *device,
00615         const struct wined3d_surface *surface, context_fbo_entry_func_t *callback)
00616 {
00617     UINT i;
00618 
00619     for (i = 0; i < device->context_count; ++i)
00620     {
00621         struct wined3d_context *context = device->contexts[i];
00622         const struct wined3d_gl_info *gl_info = context->gl_info;
00623         struct fbo_entry *entry, *entry2;
00624 
00625         if (context->current_rt == surface) context->current_rt = NULL;
00626 
00627         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
00628         {
00629             UINT j;
00630 
00631             if (entry->depth_stencil == surface)
00632             {
00633                 callback(context, entry);
00634                 continue;
00635             }
00636 
00637             for (j = 0; j < gl_info->limits.buffers; ++j)
00638             {
00639                 if (entry->render_targets[j] == surface)
00640                 {
00641                     callback(context, entry);
00642                     break;
00643                 }
00644             }
00645         }
00646     }
00647 }
00648 
00649 static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
00650 {
00651     list_remove(&entry->entry);
00652     list_add_head(&context->fbo_destroy_list, &entry->entry);
00653 }
00654 
00655 void context_resource_released(const struct wined3d_device *device,
00656         struct wined3d_resource *resource, enum wined3d_resource_type type)
00657 {
00658     if (!device->d3d_initialized) return;
00659 
00660     switch (type)
00661     {
00662         case WINED3D_RTYPE_SURFACE:
00663             context_enum_surface_fbo_entries(device, surface_from_resource(resource),
00664                     context_queue_fbo_entry_destruction);
00665             break;
00666 
00667         default:
00668             break;
00669     }
00670 }
00671 
00672 static void context_detach_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
00673 {
00674     entry->attached = FALSE;
00675 }
00676 
00677 void context_resource_unloaded(const struct wined3d_device *device,
00678         struct wined3d_resource *resource, enum wined3d_resource_type type)
00679 {
00680     switch (type)
00681     {
00682         case WINED3D_RTYPE_SURFACE:
00683             context_enum_surface_fbo_entries(device, surface_from_resource(resource),
00684                     context_detach_fbo_entry);
00685             break;
00686 
00687         default:
00688             break;
00689     }
00690 }
00691 
00692 void context_surface_update(struct wined3d_context *context, const struct wined3d_surface *surface)
00693 {
00694     const struct wined3d_gl_info *gl_info = context->gl_info;
00695     struct fbo_entry *entry = context->current_fbo;
00696     unsigned int i;
00697 
00698     if (!entry || context->rebind_fbo) return;
00699 
00700     for (i = 0; i < gl_info->limits.buffers; ++i)
00701     {
00702         if (surface == entry->render_targets[i])
00703         {
00704             TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
00705             context->rebind_fbo = TRUE;
00706             return;
00707         }
00708     }
00709 
00710     if (surface == entry->depth_stencil)
00711     {
00712         TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
00713         context->rebind_fbo = TRUE;
00714     }
00715 }
00716 
00717 static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
00718 {
00719     int current = GetPixelFormat(dc);
00720 
00721     if (current == format) return TRUE;
00722 
00723     if (!current)
00724     {
00725         if (!SetPixelFormat(dc, format, NULL))
00726         {
00727             /* This may also happen if the dc belongs to a destroyed window. */
00728             WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
00729                     format, dc, GetLastError());
00730             return FALSE;
00731         }
00732         return TRUE;
00733     }
00734 
00735     /* By default WGL doesn't allow pixel format adjustments but we need it
00736      * here. For this reason there's a Wine specific wglSetPixelFormat()
00737      * which allows us to set the pixel format multiple times. Only use it
00738      * when really needed. */
00739     if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
00740     {
00741         if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format, NULL)))
00742         {
00743             ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
00744                     format, dc);
00745             return FALSE;
00746         }
00747         return TRUE;
00748     }
00749 
00750     /* OpenGL doesn't allow pixel format adjustments. Print an error and
00751      * continue using the old format. There's a big chance that the old
00752      * format works although with a performance hit and perhaps rendering
00753      * errors. */
00754     ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
00755             format, dc, current);
00756     return TRUE;
00757 }
00758 
00759 static BOOL context_set_gl_context(struct wined3d_context *ctx)
00760 {
00761     struct wined3d_swapchain *swapchain = ctx->swapchain;
00762     BOOL backup = FALSE;
00763 
00764     if (!context_set_pixel_format(ctx->gl_info, ctx->hdc, ctx->pixel_format))
00765     {
00766         WARN("Failed to set pixel format %d on device context %p.\n",
00767                 ctx->pixel_format, ctx->hdc);
00768         backup = TRUE;
00769     }
00770 
00771     if (backup || !pwglMakeCurrent(ctx->hdc, ctx->glCtx))
00772     {
00773         HDC dc;
00774 
00775         WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
00776                 ctx->glCtx, ctx->hdc, GetLastError());
00777         ctx->valid = 0;
00778         WARN("Trying fallback to the backup window.\n");
00779 
00780         /* FIXME: If the context is destroyed it's no longer associated with
00781          * a swapchain, so we can't use the swapchain to get a backup dc. To
00782          * make this work windowless contexts would need to be handled by the
00783          * device. */
00784         if (ctx->destroyed)
00785         {
00786             FIXME("Unable to get backup dc for destroyed context %p.\n", ctx);
00787             context_set_current(NULL);
00788             return FALSE;
00789         }
00790 
00791         if (!(dc = swapchain_get_backup_dc(swapchain)))
00792         {
00793             context_set_current(NULL);
00794             return FALSE;
00795         }
00796 
00797         if (!context_set_pixel_format(ctx->gl_info, dc, ctx->pixel_format))
00798         {
00799             ERR("Failed to set pixel format %d on device context %p.\n",
00800                     ctx->pixel_format, dc);
00801             context_set_current(NULL);
00802             return FALSE;
00803         }
00804 
00805         if (!pwglMakeCurrent(dc, ctx->glCtx))
00806         {
00807             ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
00808                     dc, GetLastError());
00809             context_set_current(NULL);
00810             return FALSE;
00811         }
00812     }
00813     return TRUE;
00814 }
00815 
00816 static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx, int pf)
00817 {
00818     if (!context_set_pixel_format(gl_info, dc, pf))
00819     {
00820         ERR("Failed to restore pixel format %d on device context %p.\n", pf, dc);
00821         context_set_current(NULL);
00822         return;
00823     }
00824 
00825     if (!pwglMakeCurrent(dc, gl_ctx))
00826     {
00827         ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
00828                 gl_ctx, dc, GetLastError());
00829         context_set_current(NULL);
00830     }
00831 }
00832 
00833 static void context_update_window(struct wined3d_context *context)
00834 {
00835     if (context->win_handle == context->swapchain->win_handle)
00836         return;
00837 
00838     TRACE("Updating context %p window from %p to %p.\n",
00839             context, context->win_handle, context->swapchain->win_handle);
00840 
00841     if (context->valid)
00842     {
00843         /* You'd figure ReleaseDC() would fail if the DC doesn't match the
00844          * window. However, that's not what actually happens, and there are
00845          * user32 tests that confirm ReleaseDC() with the wrong window is
00846          * supposed to succeed. So explicitly check that the DC belongs to
00847          * the window, since we want to avoid releasing a DC that belongs to
00848          * some other window if the original window was already destroyed. */
00849         if (WindowFromDC(context->hdc) != context->win_handle)
00850         {
00851             WARN("DC %p does not belong to window %p.\n",
00852                     context->hdc, context->win_handle);
00853         }
00854         else if (!ReleaseDC(context->win_handle, context->hdc))
00855         {
00856             ERR("Failed to release device context %p, last error %#x.\n",
00857                     context->hdc, GetLastError());
00858         }
00859     }
00860     else context->valid = 1;
00861 
00862     context->win_handle = context->swapchain->win_handle;
00863 
00864     if (!(context->hdc = GetDC(context->win_handle)))
00865     {
00866         ERR("Failed to get a device context for window %p.\n", context->win_handle);
00867         goto err;
00868     }
00869 
00870     if (!context_set_pixel_format(context->gl_info, context->hdc, context->pixel_format))
00871     {
00872         ERR("Failed to set pixel format %d on device context %p.\n",
00873                 context->pixel_format, context->hdc);
00874         goto err;
00875     }
00876 
00877     context_set_gl_context(context);
00878 
00879     return;
00880 
00881 err:
00882     context->valid = 0;
00883 }
00884 
00885 /* Do not call while under the GL lock. */
00886 static void context_destroy_gl_resources(struct wined3d_context *context)
00887 {
00888     const struct wined3d_gl_info *gl_info = context->gl_info;
00889     struct wined3d_occlusion_query *occlusion_query;
00890     struct wined3d_event_query *event_query;
00891     struct fbo_entry *entry, *entry2;
00892     HGLRC restore_ctx;
00893     HDC restore_dc;
00894     unsigned int i;
00895     int restore_pf;
00896 
00897     restore_ctx = pwglGetCurrentContext();
00898     restore_dc = pwglGetCurrentDC();
00899     restore_pf = GetPixelFormat(restore_dc);
00900 
00901     if (context->valid && restore_ctx != context->glCtx)
00902         context_set_gl_context(context);
00903     else restore_ctx = NULL;
00904 
00905     ENTER_GL();
00906 
00907     LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
00908     {
00909         if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
00910             GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
00911         occlusion_query->context = NULL;
00912     }
00913 
00914     LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
00915     {
00916         if (context->valid)
00917         {
00918             if (gl_info->supported[ARB_SYNC])
00919             {
00920                 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
00921             }
00922             else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
00923             else if (gl_info->supported[NV_FENCE]) GL_EXTCALL(glDeleteFencesNV(1, &event_query->object.id));
00924         }
00925         event_query->context = NULL;
00926     }
00927 
00928     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
00929     {
00930         if (!context->valid) entry->id = 0;
00931         context_destroy_fbo_entry(context, entry);
00932     }
00933 
00934     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
00935     {
00936         if (!context->valid) entry->id = 0;
00937         context_destroy_fbo_entry(context, entry);
00938     }
00939 
00940     if (context->valid)
00941     {
00942         if (context->dummy_arbfp_prog)
00943         {
00944             GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
00945         }
00946 
00947         if (gl_info->supported[ARB_OCCLUSION_QUERY])
00948             GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
00949 
00950         if (gl_info->supported[ARB_SYNC])
00951         {
00952             for (i = 0; i < context->free_event_query_count; ++i)
00953             {
00954                 GL_EXTCALL(glDeleteSync(context->free_event_queries[i].sync));
00955             }
00956         }
00957         else if (gl_info->supported[APPLE_FENCE])
00958         {
00959             for (i = 0; i < context->free_event_query_count; ++i)
00960             {
00961                 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_event_queries[i].id));
00962             }
00963         }
00964         else if (gl_info->supported[NV_FENCE])
00965         {
00966             for (i = 0; i < context->free_event_query_count; ++i)
00967             {
00968                 GL_EXTCALL(glDeleteFencesNV(1, &context->free_event_queries[i].id));
00969             }
00970         }
00971 
00972         checkGLcall("context cleanup");
00973     }
00974 
00975     LEAVE_GL();
00976 
00977     HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
00978     HeapFree(GetProcessHeap(), 0, context->free_event_queries);
00979 
00980     if (restore_ctx)
00981     {
00982         context_restore_gl_context(gl_info, restore_dc, restore_ctx, restore_pf);
00983     }
00984     else if (pwglGetCurrentContext() && !pwglMakeCurrent(NULL, NULL))
00985     {
00986         ERR("Failed to disable GL context.\n");
00987     }
00988 
00989     ReleaseDC(context->win_handle, context->hdc);
00990 
00991     if (!pwglDeleteContext(context->glCtx))
00992     {
00993         DWORD err = GetLastError();
00994         ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
00995     }
00996 }
00997 
00998 DWORD context_get_tls_idx(void)
00999 {
01000     return wined3d_context_tls_idx;
01001 }
01002 
01003 void context_set_tls_idx(DWORD idx)
01004 {
01005     wined3d_context_tls_idx = idx;
01006 }
01007 
01008 struct wined3d_context *context_get_current(void)
01009 {
01010     return TlsGetValue(wined3d_context_tls_idx);
01011 }
01012 
01013 /* Do not call while under the GL lock. */
01014 BOOL context_set_current(struct wined3d_context *ctx)
01015 {
01016     struct wined3d_context *old = context_get_current();
01017 
01018     if (old == ctx)
01019     {
01020         TRACE("Already using D3D context %p.\n", ctx);
01021         return TRUE;
01022     }
01023 
01024     if (old)
01025     {
01026         if (old->destroyed)
01027         {
01028             TRACE("Switching away from destroyed context %p.\n", old);
01029             context_destroy_gl_resources(old);
01030             HeapFree(GetProcessHeap(), 0, (void *)old->gl_info);
01031             HeapFree(GetProcessHeap(), 0, old);
01032         }
01033         else
01034         {
01035             old->current = 0;
01036         }
01037     }
01038 
01039     if (ctx)
01040     {
01041         if (!ctx->valid)
01042         {
01043             ERR("Trying to make invalid context %p current\n", ctx);
01044             return FALSE;
01045         }
01046 
01047         TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
01048         if (!context_set_gl_context(ctx))
01049             return FALSE;
01050         ctx->current = 1;
01051     }
01052     else if(pwglGetCurrentContext())
01053     {
01054         TRACE("Clearing current D3D context.\n");
01055         if (!pwglMakeCurrent(NULL, NULL))
01056         {
01057             DWORD err = GetLastError();
01058             ERR("Failed to clear current GL context, last error %#x.\n", err);
01059             TlsSetValue(wined3d_context_tls_idx, NULL);
01060             return FALSE;
01061         }
01062     }
01063 
01064     return TlsSetValue(wined3d_context_tls_idx, ctx);
01065 }
01066 
01067 void context_release(struct wined3d_context *context)
01068 {
01069     TRACE("Releasing context %p, level %u.\n", context, context->level);
01070 
01071     if (WARN_ON(d3d))
01072     {
01073         if (!context->level)
01074             WARN("Context %p is not active.\n", context);
01075         else if (context != context_get_current())
01076             WARN("Context %p is not the current context.\n", context);
01077     }
01078 
01079     if (!--context->level && context->restore_ctx)
01080     {
01081         TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
01082         context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx, context->restore_pf);
01083         context->restore_ctx = NULL;
01084         context->restore_dc = NULL;
01085     }
01086 }
01087 
01088 static void context_enter(struct wined3d_context *context)
01089 {
01090     TRACE("Entering context %p, level %u.\n", context, context->level + 1);
01091 
01092     if (!context->level++)
01093     {
01094         const struct wined3d_context *current_context = context_get_current();
01095         HGLRC current_gl = pwglGetCurrentContext();
01096 
01097         if (current_gl && (!current_context || current_context->glCtx != current_gl))
01098         {
01099             TRACE("Another GL context (%p on device context %p) is already current.\n",
01100                     current_gl, pwglGetCurrentDC());
01101             context->restore_ctx = current_gl;
01102             context->restore_dc = pwglGetCurrentDC();
01103             context->restore_pf = GetPixelFormat(context->restore_dc);
01104         }
01105     }
01106 }
01107 
01108 void context_invalidate_state(struct wined3d_context *context, DWORD state)
01109 {
01110     DWORD rep = context->state_table[state].representative;
01111     DWORD idx;
01112     BYTE shift;
01113 
01114     if (isStateDirty(context, rep)) return;
01115 
01116     context->dirtyArray[context->numDirtyEntries++] = rep;
01117     idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
01118     shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
01119     context->isStateDirty[idx] |= (1 << shift);
01120 }
01121 
01122 /* This function takes care of wined3d pixel format selection. */
01123 static int context_choose_pixel_format(const struct wined3d_device *device, HDC hdc,
01124         const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
01125         BOOL auxBuffers, BOOL findCompatible)
01126 {
01127     int iPixelFormat=0;
01128     BYTE redBits, greenBits, blueBits, alphaBits, colorBits;
01129     BYTE depthBits=0, stencilBits=0;
01130     unsigned int current_value;
01131     unsigned int cfg_count = device->adapter->cfg_count;
01132     unsigned int i;
01133 
01134     TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x, find_compatible %#x.\n",
01135             device, hdc, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
01136             auxBuffers, findCompatible);
01137 
01138     if (!getColorBits(color_format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits))
01139     {
01140         ERR("Unable to get color bits for format %s (%#x)!\n",
01141                 debug_d3dformat(color_format->id), color_format->id);
01142         return 0;
01143     }
01144 
01145     getDepthStencilBits(ds_format, &depthBits, &stencilBits);
01146 
01147     current_value = 0;
01148     for (i = 0; i < cfg_count; ++i)
01149     {
01150         const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
01151         unsigned int value;
01152 
01153         /* For now only accept RGBA formats. Perhaps some day we will
01154          * allow floating point formats for pbuffers. */
01155         if (cfg->iPixelType != WGL_TYPE_RGBA_ARB)
01156             continue;
01157         /* In window mode we need a window drawable format and double buffering. */
01158         if (!(cfg->windowDrawable && cfg->doubleBuffer))
01159             continue;
01160         if (cfg->redSize < redBits)
01161             continue;
01162         if (cfg->greenSize < greenBits)
01163             continue;
01164         if (cfg->blueSize < blueBits)
01165             continue;
01166         if (cfg->alphaSize < alphaBits)
01167             continue;
01168         if (cfg->depthSize < depthBits)
01169             continue;
01170         if (stencilBits && cfg->stencilSize != stencilBits)
01171             continue;
01172         /* Check multisampling support. */
01173         if (cfg->numSamples)
01174             continue;
01175 
01176         value = 1;
01177         /* We try to locate a format which matches our requirements exactly. In case of
01178          * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
01179         if (cfg->depthSize == depthBits)
01180             value += 1;
01181         if (cfg->stencilSize == stencilBits)
01182             value += 2;
01183         if (cfg->alphaSize == alphaBits)
01184             value += 4;
01185         /* We like to have aux buffers in backbuffer mode */
01186         if (auxBuffers && cfg->auxBuffers)
01187             value += 8;
01188         if (cfg->redSize == redBits
01189                 && cfg->greenSize == greenBits
01190                 && cfg->blueSize == blueBits)
01191             value += 16;
01192 
01193         if (value > current_value)
01194         {
01195             iPixelFormat = cfg->iPixelFormat;
01196             current_value = value;
01197         }
01198     }
01199 
01200     /* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
01201     if(!iPixelFormat && !findCompatible) {
01202         ERR("Can't find a suitable iPixelFormat\n");
01203         return FALSE;
01204     } else if(!iPixelFormat) {
01205         PIXELFORMATDESCRIPTOR pfd;
01206 
01207         TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
01208         /* PixelFormat selection */
01209         ZeroMemory(&pfd, sizeof(pfd));
01210         pfd.nSize      = sizeof(pfd);
01211         pfd.nVersion   = 1;
01212         pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
01213         pfd.iPixelType = PFD_TYPE_RGBA;
01214         pfd.cAlphaBits = alphaBits;
01215         pfd.cColorBits = colorBits;
01216         pfd.cDepthBits = depthBits;
01217         pfd.cStencilBits = stencilBits;
01218         pfd.iLayerType = PFD_MAIN_PLANE;
01219 
01220         iPixelFormat = ChoosePixelFormat(hdc, &pfd);
01221         if(!iPixelFormat) {
01222             /* If this happens something is very wrong as ChoosePixelFormat barely fails */
01223             ERR("Can't find a suitable iPixelFormat\n");
01224             return FALSE;
01225         }
01226     }
01227 
01228     TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
01229             iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
01230     return iPixelFormat;
01231 }
01232 
01233 /* GL locking is done by the caller */
01234 static void bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
01235 {
01236     const struct wined3d_gl_info *gl_info = context->gl_info;
01237     unsigned int i, count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
01238 
01239     for (i = 0; i < count; ++i)
01240     {
01241         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
01242         checkGLcall("glActiveTextureARB");
01243 
01244         glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[i]);
01245         checkGLcall("glBindTexture");
01246 
01247         if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
01248         {
01249             glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[i]);
01250             checkGLcall("glBindTexture");
01251         }
01252 
01253         if (gl_info->supported[EXT_TEXTURE3D])
01254         {
01255             glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[i]);
01256             checkGLcall("glBindTexture");
01257         }
01258 
01259         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
01260         {
01261             glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[i]);
01262             checkGLcall("glBindTexture");
01263         }
01264     }
01265 }
01266 
01267 /* Do not call while under the GL lock. */
01268 struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
01269         struct wined3d_surface *target, const struct wined3d_format *ds_format)
01270 {
01271     struct wined3d_device *device = swapchain->device;
01272     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
01273     const struct wined3d_format *color_format;
01274     struct wined3d_context *ret;
01275     BOOL auxBuffers = FALSE;
01276     int pixel_format;
01277     unsigned int s;
01278     int swap_interval;
01279     DWORD state;
01280     HGLRC ctx;
01281     HDC hdc;
01282 
01283     TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
01284 
01285     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
01286     if (!ret)
01287     {
01288         ERR("Failed to allocate context memory.\n");
01289         return NULL;
01290     }
01291 
01292     ret->blit_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
01293             gl_info->limits.buffers * sizeof(*ret->blit_targets));
01294     if (!ret->blit_targets)
01295         goto out;
01296 
01297     ret->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
01298             gl_info->limits.buffers * sizeof(*ret->draw_buffers));
01299     if (!ret->draw_buffers)
01300         goto out;
01301 
01302     ret->free_occlusion_query_size = 4;
01303     ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
01304             ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
01305     if (!ret->free_occlusion_queries)
01306         goto out;
01307 
01308     list_init(&ret->occlusion_queries);
01309 
01310     ret->free_event_query_size = 4;
01311     ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
01312             ret->free_event_query_size * sizeof(*ret->free_event_queries));
01313     if (!ret->free_event_queries)
01314         goto out;
01315 
01316     list_init(&ret->event_queries);
01317     list_init(&ret->fbo_list);
01318     list_init(&ret->fbo_destroy_list);
01319 
01320     if (!(hdc = GetDC(swapchain->win_handle)))
01321     {
01322         WARN("Failed to retireve device context, trying swapchain backup.\n");
01323 
01324         if (!(hdc = swapchain_get_backup_dc(swapchain)))
01325         {
01326             ERR("Failed to retrieve a device context.\n");
01327             goto out;
01328         }
01329     }
01330 
01331     color_format = target->resource.format;
01332 
01333     /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
01334      * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
01335     if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
01336     {
01337         auxBuffers = TRUE;
01338 
01339         if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
01340             color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM);
01341         else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
01342             color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
01343     }
01344 
01345     /* DirectDraw supports 8bit paletted render targets and these are used by
01346      * old games like StarCraft and C&C. Most modern hardware doesn't support
01347      * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
01348      * conversion (ab)uses the alpha component for storing the palette index.
01349      * For this reason we require a format with 8bit alpha, so request
01350      * A8R8G8B8. */
01351     if (color_format->id == WINED3DFMT_P8_UINT)
01352         color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
01353 
01354     /* Try to find a pixel format which matches our requirements. */
01355     pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format, auxBuffers, FALSE);
01356 
01357     /* Try to locate a compatible format if we weren't able to find anything. */
01358     if (!pixel_format)
01359     {
01360         TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
01361         pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format, auxBuffers, TRUE);
01362     }
01363 
01364     /* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
01365     if (!pixel_format)
01366     {
01367         ERR("Can't find a suitable pixel format.\n");
01368         goto out;
01369     }
01370 
01371     context_enter(ret);
01372 
01373     if (!context_set_pixel_format(gl_info, hdc, pixel_format))
01374     {
01375         ERR("Failed to set pixel format %d on device context %p.\n", pixel_format, hdc);
01376         context_release(ret);
01377         goto out;
01378     }
01379 
01380     if (!(ctx = pwglCreateContext(hdc)))
01381     {
01382         ERR("Failed to create a WGL context.\n");
01383         context_release(ret);
01384         goto out;
01385     }
01386 
01387     if (device->context_count)
01388     {
01389         if (!pwglShareLists(device->contexts[0]->glCtx, ctx))
01390         {
01391             ERR("wglShareLists(%p, %p) failed, last error %#x.\n",
01392                     device->contexts[0]->glCtx, ctx, GetLastError());
01393             context_release(ret);
01394             if (!pwglDeleteContext(ctx))
01395                 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
01396             goto out;
01397         }
01398     }
01399 
01400     if (!device_context_add(device, ret))
01401     {
01402         ERR("Failed to add the newly created context to the context list\n");
01403         context_release(ret);
01404         if (!pwglDeleteContext(ctx))
01405             ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
01406         goto out;
01407     }
01408 
01409     ret->gl_info = gl_info;
01410     ret->state_table = device->StateTable;
01411 
01412     /* Mark all states dirty to force a proper initialization of the states
01413      * on the first use of the context. */
01414     for (state = 0; state <= STATE_HIGHEST; ++state)
01415     {
01416         if (ret->state_table[state].representative)
01417             context_invalidate_state(ret, state);
01418     }
01419 
01420     ret->swapchain = swapchain;
01421     ret->current_rt = target;
01422     ret->tid = GetCurrentThreadId();
01423 
01424     ret->render_offscreen = surface_is_offscreen(target);
01425     ret->draw_buffers_mask = context_generate_rt_mask(GL_BACK);
01426     ret->valid = 1;
01427 
01428     ret->glCtx = ctx;
01429     ret->win_handle = swapchain->win_handle;
01430     ret->hdc = hdc;
01431     ret->pixel_format = pixel_format;
01432 
01433     /* Set up the context defaults */
01434     if (!context_set_current(ret))
01435     {
01436         ERR("Cannot activate context to set up defaults.\n");
01437         device_context_remove(device, ret);
01438         context_release(ret);
01439         if (!pwglDeleteContext(ctx))
01440             ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
01441         goto out;
01442     }
01443 
01444     switch (swapchain->desc.swap_interval)
01445     {
01446         case WINED3DPRESENT_INTERVAL_IMMEDIATE:
01447             swap_interval = 0;
01448             break;
01449         case WINED3DPRESENT_INTERVAL_DEFAULT:
01450         case WINED3DPRESENT_INTERVAL_ONE:
01451             swap_interval = 1;
01452             break;
01453         case WINED3DPRESENT_INTERVAL_TWO:
01454             swap_interval = 2;
01455             break;
01456         case WINED3DPRESENT_INTERVAL_THREE:
01457             swap_interval = 3;
01458             break;
01459         case WINED3DPRESENT_INTERVAL_FOUR:
01460             swap_interval = 4;
01461             break;
01462         default:
01463             FIXME("Unknown swap interval %#x.\n", swapchain->desc.swap_interval);
01464             swap_interval = 1;
01465     }
01466 
01467     if (gl_info->supported[WGL_EXT_SWAP_CONTROL])
01468     {
01469         if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
01470             ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
01471                 swap_interval, ret, GetLastError());
01472     }
01473 
01474     ENTER_GL();
01475 
01476     glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
01477 
01478     TRACE("Setting up the screen\n");
01479     /* Clear the screen */
01480     glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
01481     checkGLcall("glClearColor");
01482     glClearIndex(0);
01483     glClearDepth(1);
01484     glClearStencil(0xffff);
01485 
01486     checkGLcall("glClear");
01487 
01488     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
01489     checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
01490 
01491     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
01492     checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
01493 
01494     glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
01495     checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
01496 
01497     glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
01498     checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
01499     glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);
01500     checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
01501 
01502     if (gl_info->supported[APPLE_CLIENT_STORAGE])
01503     {
01504         /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures
01505          * and textures in DIB sections(due to the memory protection).
01506          */
01507         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
01508         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
01509     }
01510     if (gl_info->supported[ARB_VERTEX_BLEND])
01511     {
01512         /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one
01513          * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless
01514          * GL_VERTEX_BLEND_ARB isn't enabled too
01515          */
01516         glEnable(GL_WEIGHT_SUM_UNITY_ARB);
01517         checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
01518     }
01519     if (gl_info->supported[NV_TEXTURE_SHADER2])
01520     {
01521         /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
01522          * the previous texture where to source the offset from is always unit - 1.
01523          */
01524         for (s = 1; s < gl_info->limits.textures; ++s)
01525         {
01526             context_active_texture(ret, gl_info, s);
01527             glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
01528             checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
01529         }
01530     }
01531     if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
01532     {
01533         /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
01534          * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
01535          * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
01536          * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
01537          * is ever assigned.
01538          *
01539          * So make sure a program is assigned to each context. The first real ARBFP use will set a different
01540          * program and the dummy program is destroyed when the context is destroyed.
01541          */
01542         const char *dummy_program =
01543                 "!!ARBfp1.0\n"
01544                 "MOV result.color, fragment.color.primary;\n"
01545                 "END\n";
01546         GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
01547         GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
01548         GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
01549     }
01550 
01551     if (gl_info->supported[ARB_POINT_SPRITE])
01552     {
01553         for (s = 0; s < gl_info->limits.textures; ++s)
01554         {
01555             context_active_texture(ret, gl_info, s);
01556             glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
01557             checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
01558         }
01559     }
01560 
01561     if (gl_info->supported[ARB_PROVOKING_VERTEX])
01562     {
01563         GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
01564     }
01565     else if (gl_info->supported[EXT_PROVOKING_VERTEX])
01566     {
01567         GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
01568     }
01569     device->frag_pipe->enable_extension(TRUE);
01570 
01571     /* If this happens to be the first context for the device, dummy textures
01572      * are not created yet. In that case, they will be created (and bound) by
01573      * create_dummy_textures right after this context is initialized. */
01574     if (device->dummy_texture_2d[0])
01575         bind_dummy_textures(device, ret);
01576 
01577     LEAVE_GL();
01578 
01579     TRACE("Created context %p.\n", ret);
01580 
01581     return ret;
01582 
01583 out:
01584     HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
01585     HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
01586     HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
01587     HeapFree(GetProcessHeap(), 0, ret->blit_targets);
01588     HeapFree(GetProcessHeap(), 0, ret);
01589     return NULL;
01590 }
01591 
01592 /* Do not call while under the GL lock. */
01593 void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
01594 {
01595     BOOL destroy;
01596 
01597     TRACE("Destroying ctx %p\n", context);
01598 
01599     if (context->tid == GetCurrentThreadId() || !context->current)
01600     {
01601         context_destroy_gl_resources(context);
01602         TlsSetValue(wined3d_context_tls_idx, NULL);
01603         destroy = TRUE;
01604     }
01605     else
01606     {
01607         /* Make a copy of gl_info for context_destroy_gl_resources use, the one
01608            in wined3d_adapter may go away in the meantime */
01609         struct wined3d_gl_info *gl_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*gl_info));
01610         *gl_info = *context->gl_info;
01611         context->gl_info = gl_info;
01612         context->destroyed = 1;
01613         destroy = FALSE;
01614     }
01615 
01616     HeapFree(GetProcessHeap(), 0, context->draw_buffers);
01617     HeapFree(GetProcessHeap(), 0, context->blit_targets);
01618     device_context_remove(device, context);
01619     if (destroy) HeapFree(GetProcessHeap(), 0, context);
01620 }
01621 
01622 /* GL locking is done by the caller */
01623 static void set_blit_dimension(UINT width, UINT height)
01624 {
01625     const GLdouble projection[] =
01626     {
01627         2.0 / width,          0.0,  0.0, 0.0,
01628                 0.0, 2.0 / height,  0.0, 0.0,
01629                 0.0,          0.0,  2.0, 0.0,
01630                -1.0,         -1.0, -1.0, 1.0,
01631     };
01632 
01633     glMatrixMode(GL_PROJECTION);
01634     checkGLcall("glMatrixMode(GL_PROJECTION)");
01635     glLoadMatrixd(projection);
01636     checkGLcall("glLoadMatrixd");
01637     glViewport(0, 0, width, height);
01638     checkGLcall("glViewport");
01639 }
01640 
01641 /*****************************************************************************
01642  * SetupForBlit
01643  *
01644  * Sets up a context for DirectDraw blitting.
01645  * All texture units are disabled, texture unit 0 is set as current unit
01646  * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
01647  * color writing enabled for all channels
01648  * register combiners disabled, shaders disabled
01649  * world matrix is set to identity, texture matrix 0 too
01650  * projection matrix is setup for drawing screen coordinates
01651  *
01652  * Params:
01653  *  This: Device to activate the context for
01654  *  context: Context to setup
01655  *
01656  *****************************************************************************/
01657 /* Context activation is done by the caller. */
01658 static void SetupForBlit(const struct wined3d_device *device, struct wined3d_context *context)
01659 {
01660     int i;
01661     const struct wined3d_gl_info *gl_info = context->gl_info;
01662     UINT width = context->current_rt->resource.width;
01663     UINT height = context->current_rt->resource.height;
01664     DWORD sampler;
01665 
01666     TRACE("Setting up context %p for blitting\n", context);
01667     if(context->last_was_blit) {
01668         if(context->blit_w != width || context->blit_h != height) {
01669             ENTER_GL();
01670             set_blit_dimension(width, height);
01671             LEAVE_GL();
01672             context->blit_w = width; context->blit_h = height;
01673             /* No need to dirtify here, the states are still dirtified because they weren't
01674              * applied since the last SetupForBlit call. Otherwise last_was_blit would not
01675              * be set
01676              */
01677         }
01678         TRACE("Context is already set up for blitting, nothing to do\n");
01679         return;
01680     }
01681     context->last_was_blit = TRUE;
01682 
01683     /* TODO: Use a display list */
01684 
01685     /* Disable shaders */
01686     ENTER_GL();
01687     device->shader_backend->shader_select(context, FALSE, FALSE);
01688     LEAVE_GL();
01689 
01690     context_invalidate_state(context, STATE_VSHADER);
01691     context_invalidate_state(context, STATE_PIXELSHADER);
01692 
01693     /* Call ENTER_GL() once for all gl calls below. In theory we should not call
01694      * helper functions in between gl calls. This function is full of context_invalidate_state
01695      * which can safely be called from here, we only lock once instead locking/unlocking
01696      * after each GL call.
01697      */
01698     ENTER_GL();
01699 
01700     /* Disable all textures. The caller can then bind a texture it wants to blit
01701      * from
01702      *
01703      * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
01704      * function texture unit. No need to care for higher samplers
01705      */
01706     for (i = gl_info->limits.textures - 1; i > 0 ; --i)
01707     {
01708         sampler = device->rev_tex_unit_map[i];
01709         context_active_texture(context, gl_info, i);
01710 
01711         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
01712         {
01713             glDisable(GL_TEXTURE_CUBE_MAP_ARB);
01714             checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
01715         }
01716         glDisable(GL_TEXTURE_3D);
01717         checkGLcall("glDisable GL_TEXTURE_3D");
01718         if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
01719         {
01720             glDisable(GL_TEXTURE_RECTANGLE_ARB);
01721             checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
01722         }
01723         glDisable(GL_TEXTURE_2D);
01724         checkGLcall("glDisable GL_TEXTURE_2D");
01725 
01726         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
01727         checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
01728 
01729         if (sampler != WINED3D_UNMAPPED_STAGE)
01730         {
01731             if (sampler < MAX_TEXTURES)
01732                 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
01733             context_invalidate_state(context, STATE_SAMPLER(sampler));
01734         }
01735     }
01736     context_active_texture(context, gl_info, 0);
01737 
01738     sampler = device->rev_tex_unit_map[0];
01739 
01740     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
01741     {
01742         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
01743         checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
01744     }
01745     glDisable(GL_TEXTURE_3D);
01746     checkGLcall("glDisable GL_TEXTURE_3D");
01747     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
01748     {
01749         glDisable(GL_TEXTURE_RECTANGLE_ARB);
01750         checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
01751     }
01752     glDisable(GL_TEXTURE_2D);
01753     checkGLcall("glDisable GL_TEXTURE_2D");
01754 
01755     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
01756 
01757     glMatrixMode(GL_TEXTURE);
01758     checkGLcall("glMatrixMode(GL_TEXTURE)");
01759     glLoadIdentity();
01760     checkGLcall("glLoadIdentity()");
01761 
01762     if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
01763     {
01764         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
01765                   GL_TEXTURE_LOD_BIAS_EXT,
01766                   0.0f);
01767         checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
01768     }
01769 
01770     if (sampler != WINED3D_UNMAPPED_STAGE)
01771     {
01772         if (sampler < MAX_TEXTURES)
01773         {
01774             context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_TEXTURE0 + sampler));
01775             context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
01776         }
01777         context_invalidate_state(context, STATE_SAMPLER(sampler));
01778     }
01779 
01780     /* Other misc states */
01781     glDisable(GL_ALPHA_TEST);
01782     checkGLcall("glDisable(GL_ALPHA_TEST)");
01783     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHATESTENABLE));
01784     glDisable(GL_LIGHTING);
01785     checkGLcall("glDisable GL_LIGHTING");
01786     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_LIGHTING));
01787     glDisable(GL_DEPTH_TEST);
01788     checkGLcall("glDisable GL_DEPTH_TEST");
01789     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZENABLE));
01790     glDisableWINE(GL_FOG);
01791     checkGLcall("glDisable GL_FOG");
01792     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_FOGENABLE));
01793     glDisable(GL_BLEND);
01794     checkGLcall("glDisable GL_BLEND");
01795     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
01796     glDisable(GL_CULL_FACE);
01797     checkGLcall("glDisable GL_CULL_FACE");
01798     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CULLMODE));
01799     glDisable(GL_STENCIL_TEST);
01800     checkGLcall("glDisable GL_STENCIL_TEST");
01801     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILENABLE));
01802     glDisable(GL_SCISSOR_TEST);
01803     checkGLcall("glDisable GL_SCISSOR_TEST");
01804     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
01805     if (gl_info->supported[ARB_POINT_SPRITE])
01806     {
01807         glDisable(GL_POINT_SPRITE_ARB);
01808         checkGLcall("glDisable GL_POINT_SPRITE_ARB");
01809         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE));
01810     }
01811     glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
01812     checkGLcall("glColorMask");
01813     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
01814     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
01815     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
01816     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
01817     if (gl_info->supported[EXT_SECONDARY_COLOR])
01818     {
01819         glDisable(GL_COLOR_SUM_EXT);
01820         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SPECULARENABLE));
01821         checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
01822     }
01823 
01824     /* Setup transforms */
01825     glMatrixMode(GL_MODELVIEW);
01826     checkGLcall("glMatrixMode(GL_MODELVIEW)");
01827     glLoadIdentity();
01828     checkGLcall("glLoadIdentity()");
01829     context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)));
01830 
01831     context->last_was_rhw = TRUE;
01832     context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
01833 
01834     glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
01835     glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
01836     glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
01837     glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
01838     glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
01839     glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
01840     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CLIPPING));
01841 
01842     set_blit_dimension(width, height);
01843     device->frag_pipe->enable_extension(FALSE);
01844 
01845     LEAVE_GL();
01846 
01847     context->blit_w = width; context->blit_h = height;
01848     context_invalidate_state(context, STATE_VIEWPORT);
01849     context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
01850 }
01851 
01852 static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
01853 {
01854     return rt_mask & (1 << 31);
01855 }
01856 
01857 static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
01858 {
01859     return rt_mask & ~(1 << 31);
01860 }
01861 
01862 /* Context activation and GL locking are done by the caller. */
01863 static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
01864 {
01865     if (!rt_mask)
01866     {
01867         glDrawBuffer(GL_NONE);
01868         checkGLcall("glDrawBuffer()");
01869     }
01870     else if (is_rt_mask_onscreen(rt_mask))
01871     {
01872         glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
01873         checkGLcall("glDrawBuffer()");
01874     }
01875     else
01876     {
01877         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
01878         {
01879             const struct wined3d_gl_info *gl_info = context->gl_info;
01880             unsigned int i = 0;
01881 
01882             while (rt_mask)
01883             {
01884                 if (rt_mask & 1)
01885                     context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
01886                 else
01887                     context->draw_buffers[i] = GL_NONE;
01888 
01889                 rt_mask >>= 1;
01890                 ++i;
01891             }
01892 
01893             if (gl_info->supported[ARB_DRAW_BUFFERS])
01894             {
01895                 GL_EXTCALL(glDrawBuffersARB(i, context->draw_buffers));
01896                 checkGLcall("glDrawBuffers()");
01897             }
01898             else
01899             {
01900                 glDrawBuffer(context->draw_buffers[0]);
01901                 checkGLcall("glDrawBuffer()");
01902             }
01903         }
01904         else
01905         {
01906             ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
01907         }
01908     }
01909 }
01910 
01911 /* GL locking is done by the caller. */
01912 void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
01913 {
01914     glDrawBuffer(buffer);
01915     checkGLcall("glDrawBuffer()");
01916     if (context->current_fbo)
01917         context->current_fbo->rt_mask = context_generate_rt_mask(buffer);
01918     else
01919         context->draw_buffers_mask = context_generate_rt_mask(buffer);
01920 }
01921 
01922 /* GL locking is done by the caller. */
01923 void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
01924 {
01925     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0 + unit));
01926     checkGLcall("glActiveTextureARB");
01927     context->active_texture = unit;
01928 }
01929 
01930 void context_bind_texture(struct wined3d_context *context, GLenum target, GLuint name)
01931 {
01932     DWORD unit = context->active_texture;
01933     DWORD old_texture_type = context->texture_type[unit];
01934 
01935     if (name)
01936     {
01937         glBindTexture(target, name);
01938         checkGLcall("glBindTexture");
01939     }
01940     else
01941     {
01942         target = GL_NONE;
01943     }
01944 
01945     if (old_texture_type != target)
01946     {
01947         const struct wined3d_device *device = context->swapchain->device;
01948 
01949         switch (old_texture_type)
01950         {
01951             case GL_NONE:
01952                 /* nothing to do */
01953                 break;
01954             case GL_TEXTURE_2D:
01955                 glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[unit]);
01956                 checkGLcall("glBindTexture");
01957                 break;
01958             case GL_TEXTURE_RECTANGLE_ARB:
01959                 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[unit]);
01960                 checkGLcall("glBindTexture");
01961                 break;
01962             case GL_TEXTURE_CUBE_MAP:
01963                 glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[unit]);
01964                 checkGLcall("glBindTexture");
01965                 break;
01966             case GL_TEXTURE_3D:
01967                 glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[unit]);
01968                 checkGLcall("glBindTexture");
01969                 break;
01970             default:
01971                 ERR("Unexpected texture target %#x\n", old_texture_type);
01972         }
01973 
01974         context->texture_type[unit] = target;
01975     }
01976 }
01977 
01978 static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
01979 {
01980     if (context->render_offscreen == offscreen) return;
01981 
01982     context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
01983     context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
01984     context_invalidate_state(context, STATE_VIEWPORT);
01985     context_invalidate_state(context, STATE_SCISSORRECT);
01986     context_invalidate_state(context, STATE_FRONTFACE);
01987     context->render_offscreen = offscreen;
01988 }
01989 
01990 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
01991         const struct wined3d_format *required)
01992 {
01993     BYTE existing_depth, existing_stencil, required_depth, required_stencil;
01994 
01995     if (existing == required) return TRUE;
01996     if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
01997 
01998     getDepthStencilBits(existing, &existing_depth, &existing_stencil);
01999     getDepthStencilBits(required, &required_depth, &required_stencil);
02000 
02001     if(existing_depth < required_depth) return FALSE;
02002     /* If stencil bits are used the exact amount is required - otherwise wrapping
02003      * won't work correctly */
02004     if(required_stencil && required_stencil != existing_stencil) return FALSE;
02005     return TRUE;
02006 }
02007 
02008 /* The caller provides a context */
02009 static void context_validate_onscreen_formats(struct wined3d_context *context,
02010         const struct wined3d_surface *depth_stencil)
02011 {
02012     /* Onscreen surfaces are always in a swapchain */
02013     struct wined3d_swapchain *swapchain = context->current_rt->container.u.swapchain;
02014 
02015     if (context->render_offscreen || !depth_stencil) return;
02016     if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format)) return;
02017 
02018     /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
02019      * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
02020      * format. */
02021     WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
02022 
02023     /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
02024     surface_load_location(context->current_rt, SFLAG_INTEXTURE, NULL);
02025     swapchain->render_to_fbo = TRUE;
02026     swapchain_update_draw_bindings(swapchain);
02027     context_set_render_offscreen(context, TRUE);
02028 }
02029 
02030 static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_device *device, const struct wined3d_surface *rt)
02031 {
02032     if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
02033         return 0;
02034     else if (rt->container.type == WINED3D_CONTAINER_SWAPCHAIN)
02035         return context_generate_rt_mask_from_surface(rt);
02036     else
02037         return context_generate_rt_mask(device->offscreenBuffer);
02038 }
02039 
02040 /* Context activation is done by the caller. */
02041 void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
02042 {
02043     struct wined3d_surface *rt = context->current_rt;
02044     DWORD rt_mask, old_mask;
02045 
02046     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02047     {
02048         context_validate_onscreen_formats(context, NULL);
02049 
02050         if (context->render_offscreen)
02051         {
02052             surface_internal_preload(rt, SRGB_RGB);
02053 
02054             ENTER_GL();
02055             context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, rt, NULL, rt->draw_binding);
02056             LEAVE_GL();
02057             if (rt->resource.format->id != WINED3DFMT_NULL)
02058                 rt_mask = 1;
02059             else
02060                 rt_mask = 0;
02061         }
02062         else
02063         {
02064             ENTER_GL();
02065             context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
02066             LEAVE_GL();
02067             rt_mask = context_generate_rt_mask_from_surface(rt);
02068         }
02069     }
02070     else
02071     {
02072         rt_mask = context_generate_rt_mask_no_fbo(device, rt);
02073     }
02074 
02075     old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
02076 
02077     ENTER_GL();
02078     if (rt_mask != old_mask)
02079     {
02080         context_apply_draw_buffers(context, rt_mask);
02081         context->draw_buffers_mask = rt_mask;
02082     }
02083 
02084     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02085     {
02086         context_check_fbo_status(context, GL_FRAMEBUFFER);
02087     }
02088     LEAVE_GL();
02089 
02090     SetupForBlit(device, context);
02091     context_invalidate_state(context, STATE_FRAMEBUFFER);
02092 }
02093 
02094 static BOOL context_validate_rt_config(UINT rt_count,
02095         struct wined3d_surface * const *rts, const struct wined3d_surface *ds)
02096 {
02097     unsigned int i;
02098 
02099     if (ds) return TRUE;
02100 
02101     for (i = 0; i < rt_count; ++i)
02102     {
02103         if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
02104             return TRUE;
02105     }
02106 
02107     WARN("Invalid render target config, need at least one attachment.\n");
02108     return FALSE;
02109 }
02110 
02111 /* Context activation is done by the caller. */
02112 BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device,
02113         UINT rt_count, const struct wined3d_fb_state *fb)
02114 {
02115     DWORD rt_mask = 0, old_mask;
02116     UINT i;
02117     struct wined3d_surface **rts = fb->render_targets;
02118 
02119     if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != &device->fb
02120             || rt_count != context->gl_info->limits.buffers)
02121     {
02122         if (!context_validate_rt_config(rt_count, rts, fb->depth_stencil))
02123             return FALSE;
02124 
02125         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02126         {
02127             context_validate_onscreen_formats(context, fb->depth_stencil);
02128 
02129             ENTER_GL();
02130 
02131             if (!rt_count || surface_is_offscreen(rts[0]))
02132             {
02133                 for (i = 0; i < rt_count; ++i)
02134                 {
02135                     context->blit_targets[i] = rts[i];
02136                     if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
02137                         rt_mask |= (1 << i);
02138                 }
02139                 while (i < context->gl_info->limits.buffers)
02140                 {
02141                     context->blit_targets[i] = NULL;
02142                     ++i;
02143                 }
02144                 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, fb->depth_stencil,
02145                         rt_count ? rts[0]->draw_binding : SFLAG_INTEXTURE);
02146                 glReadBuffer(GL_NONE);
02147                 checkGLcall("glReadBuffer");
02148             }
02149             else
02150             {
02151                 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
02152                 rt_mask = context_generate_rt_mask_from_surface(rts[0]);
02153             }
02154 
02155             LEAVE_GL();
02156 
02157             /* If the framebuffer is not the device's fb the device's fb has to be reapplied
02158              * next draw. Otherwise we could mark the framebuffer state clean here, once the
02159              * state management allows this */
02160             context_invalidate_state(context, STATE_FRAMEBUFFER);
02161         }
02162         else
02163         {
02164             rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
02165         }
02166     }
02167     else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
02168             && (!rt_count || surface_is_offscreen(rts[0])))
02169     {
02170         for (i = 0; i < rt_count; ++i)
02171         {
02172             if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) rt_mask |= (1 << i);
02173         }
02174     }
02175     else
02176     {
02177         rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
02178     }
02179 
02180     old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
02181 
02182     ENTER_GL();
02183     if (rt_mask != old_mask)
02184     {
02185         context_apply_draw_buffers(context, rt_mask);
02186         context->draw_buffers_mask = rt_mask;
02187         context_invalidate_state(context, STATE_FRAMEBUFFER);
02188     }
02189 
02190     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02191     {
02192         context_check_fbo_status(context, GL_FRAMEBUFFER);
02193     }
02194 
02195     if (context->last_was_blit)
02196     {
02197         device->frag_pipe->enable_extension(TRUE);
02198         context->last_was_blit = FALSE;
02199     }
02200 
02201     /* Blending and clearing should be orthogonal, but tests on the nvidia
02202      * driver show that disabling blending when clearing improves the clearing
02203      * performance incredibly. */
02204     glDisable(GL_BLEND);
02205     glEnable(GL_SCISSOR_TEST);
02206     checkGLcall("glEnable GL_SCISSOR_TEST");
02207     LEAVE_GL();
02208 
02209     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
02210     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
02211     context_invalidate_state(context, STATE_SCISSORRECT);
02212 
02213     return TRUE;
02214 }
02215 
02216 static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device)
02217 {
02218     const struct wined3d_state *state = &device->stateBlock->state;
02219     struct wined3d_surface **rts = state->fb->render_targets;
02220     struct wined3d_shader *ps = state->pixel_shader;
02221     DWORD rt_mask, rt_mask_bits;
02222     unsigned int i;
02223 
02224     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return context_generate_rt_mask_no_fbo(device, rts[0]);
02225     else if (!context->render_offscreen) return context_generate_rt_mask_from_surface(rts[0]);
02226 
02227     rt_mask = ps ? ps->reg_maps.rt_mask : 1;
02228     rt_mask &= device->valid_rt_mask;
02229     rt_mask_bits = rt_mask;
02230     i = 0;
02231     while (rt_mask_bits)
02232     {
02233         rt_mask_bits &= ~(1 << i);
02234         if (!rts[i] || rts[i]->resource.format->id == WINED3DFMT_NULL)
02235             rt_mask &= ~(1 << i);
02236 
02237         i++;
02238     }
02239 
02240     return rt_mask;
02241 }
02242 
02243 /* GL locking and context activation are done by the caller */
02244 void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
02245 {
02246     const struct wined3d_device *device = context->swapchain->device;
02247     const struct wined3d_fb_state *fb = state->fb;
02248     DWORD rt_mask = find_draw_buffers_mask(context, device);
02249     DWORD old_mask;
02250 
02251     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02252     {
02253         if (!context->render_offscreen)
02254         {
02255             context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
02256         }
02257         else
02258         {
02259             context_apply_fbo_state(context, GL_FRAMEBUFFER, fb->render_targets, fb->depth_stencil,
02260                     fb->render_targets[0]->draw_binding);
02261             glReadBuffer(GL_NONE);
02262             checkGLcall("glReadBuffer");
02263         }
02264     }
02265 
02266     old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
02267     if (rt_mask != old_mask)
02268     {
02269         context_apply_draw_buffers(context, rt_mask);
02270         context->draw_buffers_mask = rt_mask;
02271     }
02272 }
02273 
02274 /* GL locking and context activation are done by the caller */
02275 void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
02276 {
02277     const struct wined3d_device *device = context->swapchain->device;
02278     DWORD rt_mask, old_mask;
02279 
02280     if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
02281 
02282     old_mask = context->current_fbo ? context->current_fbo->rt_mask : context->draw_buffers_mask;
02283     rt_mask = find_draw_buffers_mask(context, device);
02284     if (rt_mask != old_mask)
02285     {
02286         context_apply_draw_buffers(context, rt_mask);
02287         context->draw_buffers_mask = rt_mask;
02288     }
02289 }
02290 
02291 /* Context activation is done by the caller. */
02292 BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
02293 {
02294     const struct wined3d_state *state = &device->stateBlock->state;
02295     const struct StateEntry *state_table = context->state_table;
02296     const struct wined3d_fb_state *fb = state->fb;
02297     unsigned int i;
02298 
02299     if (!context_validate_rt_config(context->gl_info->limits.buffers,
02300             fb->render_targets, fb->depth_stencil))
02301         return FALSE;
02302 
02303     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
02304     {
02305         context_validate_onscreen_formats(context, fb->depth_stencil);
02306     }
02307 
02308     /* Preload resources before FBO setup. Texture preload in particular may
02309      * result in changes to the current FBO, due to using e.g. FBO blits for
02310      * updating a resource location. */
02311     device_update_tex_unit_map(device);
02312     device_preload_textures(device);
02313     if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC))
02314         device_update_stream_info(device, context->gl_info);
02315 
02316     ENTER_GL();
02317     if (context->last_was_blit)
02318     {
02319         device->frag_pipe->enable_extension(TRUE);
02320     }
02321 
02322     for (i = 0; i < context->numDirtyEntries; ++i)
02323     {
02324         DWORD rep = context->dirtyArray[i];
02325         DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
02326         BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
02327         context->isStateDirty[idx] &= ~(1 << shift);
02328         state_table[rep].apply(context, state, rep);
02329     }
02330 
02331     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
02332     {
02333         context_check_fbo_status(context, GL_FRAMEBUFFER);
02334     }
02335 
02336     LEAVE_GL();
02337     context->numDirtyEntries = 0; /* This makes the whole list clean */
02338     context->last_was_blit = FALSE;
02339 
02340     return TRUE;
02341 }
02342 
02343 static void context_setup_target(struct wined3d_context *context, struct wined3d_surface *target)
02344 {
02345     BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
02346 
02347     render_offscreen = surface_is_offscreen(target);
02348     if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
02349 
02350     /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
02351      * the alpha blend state changes with different render target formats. */
02352     if (!context->current_rt)
02353     {
02354         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
02355     }
02356     else
02357     {
02358         const struct wined3d_format *old = context->current_rt->resource.format;
02359         const struct wined3d_format *new = target->resource.format;
02360 
02361         if (old->id != new->id)
02362         {
02363             /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
02364             if ((old->alpha_mask && !new->alpha_mask) || (!old->alpha_mask && new->alpha_mask)
02365                     || !(new->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
02366                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
02367 
02368             /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
02369             if ((old->flags & WINED3DFMT_FLAG_SRGB_WRITE) != (new->flags & WINED3DFMT_FLAG_SRGB_WRITE))
02370                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
02371         }
02372 
02373         /* When switching away from an offscreen render target, and we're not
02374          * using FBOs, we have to read the drawable into the texture. This is
02375          * done via PreLoad (and SFLAG_INDRAWABLE set on the surface). There
02376          * are some things that need care though. PreLoad needs a GL context,
02377          * and FindContext is called before the context is activated. It also
02378          * has to be called with the old rendertarget active, otherwise a
02379          * wrong drawable is read. */
02380         if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
02381                 && old_render_offscreen && context->current_rt != target)
02382         {
02383             /* Read the back buffer of the old drawable into the destination texture. */
02384             if (context->current_rt->texture_name_srgb)
02385                 surface_internal_preload(context->current_rt, SRGB_SRGB);
02386             surface_internal_preload(context->current_rt, SRGB_RGB);
02387             surface_modify_location(context->current_rt, SFLAG_INDRAWABLE, FALSE);
02388         }
02389     }
02390 
02391     context->current_rt = target;
02392     context_set_render_offscreen(context, render_offscreen);
02393 }
02394 
02395 /* Do not call while under the GL lock. */
02396 struct wined3d_context *context_acquire(const struct wined3d_device *device, struct wined3d_surface *target)
02397 {
02398     struct wined3d_context *current_context = context_get_current();
02399     struct wined3d_context *context;
02400 
02401     TRACE("device %p, target %p.\n", device, target);
02402 
02403     if (current_context && current_context->destroyed)
02404         current_context = NULL;
02405 
02406     if (!target)
02407     {
02408         if (current_context
02409                 && current_context->current_rt
02410                 && current_context->swapchain->device == device)
02411         {
02412             target = current_context->current_rt;
02413         }
02414         else
02415         {
02416             struct wined3d_swapchain *swapchain = device->swapchains[0];
02417             if (swapchain->back_buffers)
02418                 target = swapchain->back_buffers[0];
02419             else
02420                 target = swapchain->front_buffer;
02421         }
02422     }
02423 
02424     if (current_context && current_context->current_rt == target)
02425     {
02426         context = current_context;
02427     }
02428     else if (target->container.type == WINED3D_CONTAINER_SWAPCHAIN)
02429     {
02430         TRACE("Rendering onscreen.\n");
02431 
02432         context = swapchain_get_context(target->container.u.swapchain);
02433     }
02434     else
02435     {
02436         TRACE("Rendering offscreen.\n");
02437 
02438         /* Stay with the current context if possible. Otherwise use the
02439          * context for the primary swapchain. */
02440         if (current_context && current_context->swapchain->device == device)
02441             context = current_context;
02442         else
02443             context = swapchain_get_context(device->swapchains[0]);
02444     }
02445 
02446     context_update_window(context);
02447     context_setup_target(context, target);
02448     context_enter(context);
02449     if (!context->valid) return context;
02450 
02451     if (context != current_context)
02452     {
02453         if (!context_set_current(context))
02454         {
02455             ERR("Failed to activate the new context.\n");
02456         }
02457         else
02458         {
02459             ENTER_GL();
02460             device->frag_pipe->enable_extension(!context->last_was_blit);
02461             LEAVE_GL();
02462         }
02463     }
02464     else if (context->restore_ctx)
02465     {
02466         context_set_gl_context(context);
02467     }
02468 
02469     return context;
02470 }

Generated on Sun May 27 2012 04:20:11 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.