Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencontext.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
1.7.6.1
|