/*********************************************************************** * glGetString (OPENGL32.@) */ const GLubyte * WINAPI wine_glGetString( GLenum name ) { const GLubyte *ret; const char* GL_Extensions = NULL; /* this is for buggy nvidia driver, crashing if called from a different thread with no context */ if(wglGetCurrentContext() == NULL) return NULL; if (GL_EXTENSIONS != name) { ENTER_GL(); ret = glGetString(name); LEAVE_GL(); return ret; } if (NULL == internal_gl_extensions) { ENTER_GL(); GL_Extensions = (const char *) glGetString(GL_EXTENSIONS); if (GL_Extensions) { size_t len = strlen(GL_Extensions); internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2); TRACE("GL_EXTENSIONS reported:\n"); while (*GL_Extensions != 0x00) { const char* Start = GL_Extensions; char ThisExtn[256]; while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) { GL_Extensions++; } memcpy(ThisExtn, Start, (GL_Extensions - Start)); ThisExtn[GL_Extensions - Start] = 0; TRACE("- %s:", ThisExtn); /* test if supported API is disabled by config */ if (!internal_gl_disabled_extensions || !strstr(internal_gl_disabled_extensions, ThisExtn)) { strcat(internal_gl_extensions, " "); strcat(internal_gl_extensions, ThisExtn); TRACE(" active\n"); } else { TRACE(" deactived (by config)\n"); } if (*GL_Extensions == ' ') GL_Extensions++; } } LEAVE_GL(); } return (const GLubyte *) internal_gl_extensions; }
static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { /* Override the IWineD3DResource PreLoad method */ unsigned int i; BOOL setGlTextureDesc = FALSE; IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; TRACE("(%p) : About to load texture\n", This); if (This->baseTexture.textureName == 0) setGlTextureDesc = TRUE; IWineD3DTexture_BindTexture(iface); ENTER_GL(); /* If were dirty then reload the surfaces */ if(This->baseTexture.dirty != FALSE) { for (i = 0; i < This->baseTexture.levels; i++) { if(setGlTextureDesc) IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], This->baseTexture.textureName, IWineD3DTexture_GetTextureDimensions(iface)); IWineD3DSurface_LoadTexture(This->surfaces[i]); } /* No longer dirty */ This->baseTexture.dirty = FALSE; } else { TRACE("(%p) Texture not dirty, nothing to do\n" , iface); } LEAVE_GL(); return ; }
/* A GL context is provided by the caller */ static void gltexture_delete(struct gl_texture *tex) { ENTER_GL(); glDeleteTextures(1, &tex->name); LEAVE_GL(); tex->name = 0; }
/* Context activation is done by the caller. */ static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, int gl_level, BOOL srgb_mode) { IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info; const struct wined3d_format *format = This->resource.format; TRACE("iface %p, level %u, srgb %#x, format %s (%#x).\n", iface, gl_level, srgb_mode, debug_d3dformat(format->id), format->id); volume_bind_and_dirtify(iface); TRACE("Calling glTexImage3D %x level=%d, intfmt=%x, w=%d, h=%d,d=%d, 0=%d, glFmt=%x, glType=%x, Mem=%p\n", GL_TEXTURE_3D, gl_level, format->glInternal, This->currentDesc.Width, This->currentDesc.Height, This->currentDesc.Depth, 0, format->glFormat, format->glType, This->resource.allocatedMemory); ENTER_GL(); GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, gl_level, format->glInternal, This->currentDesc.Width, This->currentDesc.Height, This->currentDesc.Depth, 0, format->glFormat, format->glType, This->resource.allocatedMemory)); checkGLcall("glTexImage3D"); LEAVE_GL(); /* When adding code releasing This->resource.allocatedMemory to save data keep in mind that * GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by default if supported(GL_APPLE_client_storage). * Thus do not release This->resource.allocatedMemory if GL_APPLE_client_storage is supported. */ return WINED3D_OK; }
/* Context activation is done by the caller. */ static void volume_bind_and_dirtify(IWineD3DVolume *iface) { IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info; DWORD active_sampler; /* We don't need a specific texture unit, but after binding the texture the current unit is dirty. * Read the unit back instead of switching to 0, this avoids messing around with the state manager's * gl states. The current texture unit should always be a valid one. * * To be more specific, this is tricky because we can implicitly be called * from sampler() in state.c. This means we can't touch anything other than * whatever happens to be the currently active texture, or we would risk * marking already applied sampler states dirty again. * * TODO: Track the current active texture per GL context instead of using glGet */ if (gl_info->supported[ARB_MULTITEXTURE]) { GLint active_texture; ENTER_GL(); glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture); LEAVE_GL(); active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB]; } else { active_sampler = 0; } if (active_sampler != WINED3D_UNMAPPED_STAGE) { IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler)); } IWineD3DVolumeTexture_BindTexture((IWineD3DVolumeTexture *)This->container, FALSE); }
/* Context activation is done by the caller. */ static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface, BOOL srgb) { IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; BOOL set_gl_texture_desc; HRESULT hr; TRACE("(%p) : relay to BaseTexture\n", This); #ifdef VBOX_WITH_WDDM Assert(!VBOXSHRC_IS_DISABLED(This)); #endif hr = basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &set_gl_texture_desc); if (set_gl_texture_desc && SUCCEEDED(hr)) { UINT i; struct gl_texture *gl_tex; if(This->baseTexture.is_srgb) { gl_tex = &This->baseTexture.texture_srgb; } else { gl_tex = &This->baseTexture.texture_rgb; } for (i = 0; i < This->baseTexture.levels; ++i) { surface_set_texture_name(This->surfaces[i], gl_tex->name, This->baseTexture.is_srgb); } /* Conditinal non power of two textures use a different clamping default. If we're using the GL_WINE_normalized_texrect * partial driver emulation, we're dealing with a GL_TEXTURE_2D texture which has the address mode set to repeat - something * that prevents us from hitting the accelerated codepath. Thus manually set the GL state. The same applies to filtering. * Even if the texture has only one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW fallback on macos. */ if(IWineD3DBaseTexture_IsCondNP2(iface)) { #ifdef VBOX_WITH_WDDM if (!VBOXSHRC_IS_SHARED_OPENED(This)) #endif { ENTER_GL(); glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)"); glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)"); glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)"); glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)"); LEAVE_GL(); } gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE; } } return hr; }
/* Context activation is done by the caller. */ static HRESULT texture2d_bind(struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info, BOOL srgb) { BOOL set_gl_texture_desc; HRESULT hr; TRACE("texture %p, gl_info %p, srgb %#x.\n", texture, gl_info, srgb); hr = wined3d_texture_bind(texture, gl_info, srgb, &set_gl_texture_desc); if (set_gl_texture_desc && SUCCEEDED(hr)) { UINT sub_count = texture->level_count * texture->layer_count; BOOL srgb_tex = !gl_info->supported[EXT_TEXTURE_SRGB_DECODE] && (texture->flags & WINED3D_TEXTURE_IS_SRGB); struct gl_texture *gl_tex; UINT i; gl_tex = wined3d_texture_get_gl_texture(texture, gl_info, srgb_tex); for (i = 0; i < sub_count; ++i) { struct wined3d_surface *surface = surface_from_resource(texture->sub_resources[i]); surface_set_texture_name(surface, gl_tex->name, srgb_tex); } /* Conditinal non power of two textures use a different clamping * default. If we're using the GL_WINE_normalized_texrect partial * driver emulation, we're dealing with a GL_TEXTURE_2D texture which * has the address mode set to repeat - something that prevents us * from hitting the accelerated codepath. Thus manually set the GL * state. The same applies to filtering. Even if the texture has only * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW * fallback on macos. */ if (texture->flags & WINED3D_TEXTURE_COND_NP2) { GLenum target = texture->target; ENTER_GL(); glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)"); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)"); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)"); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)"); LEAVE_GL(); gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE; } } return hr; }
/* Context activation is done by the caller. */ static HRESULT texture_bind(IWineD3DBaseTextureImpl *texture, BOOL srgb) { BOOL set_gl_texture_desc; HRESULT hr; TRACE("texture %p, srgb %#x.\n", texture, srgb); hr = basetexture_bind(texture, srgb, &set_gl_texture_desc); if (set_gl_texture_desc && SUCCEEDED(hr)) { UINT i; struct gl_texture *gl_tex; if (texture->baseTexture.is_srgb) gl_tex = &texture->baseTexture.texture_srgb; else gl_tex = &texture->baseTexture.texture_rgb; for (i = 0; i < texture->baseTexture.level_count; ++i) { IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i]; surface_set_texture_name(surface, gl_tex->name, texture->baseTexture.is_srgb); } /* Conditinal non power of two textures use a different clamping * default. If we're using the GL_WINE_normalized_texrect partial * driver emulation, we're dealing with a GL_TEXTURE_2D texture which * has the address mode set to repeat - something that prevents us * from hitting the accelerated codepath. Thus manually set the GL * state. The same applies to filtering. Even if the texture has only * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW * fallback on macos. */ if (IWineD3DBaseTexture_IsCondNP2((IWineD3DBaseTexture *)texture)) { GLenum target = texture->baseTexture.target; ENTER_GL(); glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)"); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)"); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)"); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkGLcall("glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)"); LEAVE_GL(); gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_CLAMP; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE; } } return hr; }
void wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) { const struct wined3d_gl_info *gl_info; struct wined3d_context *context; if (query->context) { if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId()) { #ifdef VBOX_WINE_WITH_SINGLE_CONTEXT ERR("unexpected\n"); #endif context_free_event_query(query); context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); context_alloc_event_query(context, query); } else { context = context_acquire(device, query->context->current_rt, CTXUSAGE_RESOURCELOAD); } } else { context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); context_alloc_event_query(context, query); } gl_info = context->gl_info; ENTER_GL(); if (gl_info->supported[ARB_SYNC]) { if (query->object.sync) GL_EXTCALL(glDeleteSync(query->object.sync)); checkGLcall("glDeleteSync"); query->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); checkGLcall("glFenceSync"); } else if (gl_info->supported[APPLE_FENCE]) { GL_EXTCALL(glSetFenceAPPLE(query->object.id)); checkGLcall("glSetFenceAPPLE"); } else if (gl_info->supported[NV_FENCE]) { GL_EXTCALL(glSetFenceNV(query->object.id, GL_ALL_COMPLETED_NV)); checkGLcall("glSetFenceNV"); } LEAVE_GL(); context_release(context); }
HRESULT basetexture_set_autogen_filter_type(IWineD3DBaseTextureImpl *texture, WINED3DTEXTUREFILTERTYPE filter_type) { TRACE("texture %p, filter_type %s.\n", texture, debug_d3dtexturefiltertype(filter_type)); if (!(texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) { WARN("Texture doesn't have AUTOGENMIPMAP usage.\n"); return WINED3DERR_INVALIDCALL; } if (texture->baseTexture.filterType != filter_type) { GLenum target = texture->baseTexture.target; struct wined3d_context *context; context = context_acquire(texture->resource.device, NULL); ENTER_GL(); glBindTexture(target, texture->baseTexture.texture_rgb.name); checkGLcall("glBindTexture"); switch (filter_type) { case WINED3DTEXF_NONE: case WINED3DTEXF_POINT: glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST); checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST)"); break; case WINED3DTEXF_LINEAR: glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); break; default: WARN("Unexpected filter type %#x, setting to GL_NICEST.\n", filter_type); glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); break; } LEAVE_GL(); context_release(context); } texture->baseTexture.filterType = filter_type; return WINED3D_OK; }
HRESULT basetexture_set_autogen_filter_type(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; IWineD3DDeviceImpl *device = This->resource.device; GLenum textureDimensions = This->baseTexture.target; if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) { TRACE("(%p) : returning invalid call\n", This); return WINED3DERR_INVALIDCALL; } if(This->baseTexture.filterType != FilterType) { /* What about multithreading? Do we want all the context overhead just to set this value? * Or should we delay the applying until the texture is used for drawing? For now, apply * immediately. */ struct wined3d_context *context = context_acquire(device, NULL); ENTER_GL(); glBindTexture(textureDimensions, This->baseTexture.texture_rgb.name); checkGLcall("glBindTexture"); switch(FilterType) { case WINED3DTEXF_NONE: case WINED3DTEXF_POINT: glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST)"); break; case WINED3DTEXF_LINEAR: glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); break; default: WARN("Unexpected filter type %d, setting to GL_NICEST\n", FilterType); glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); } LEAVE_GL(); context_release(context); } This->baseTexture.filterType = FilterType; TRACE("(%p) :\n", This); return WINED3D_OK; }
/* Context activation is done by the caller. */ void volume_load(const struct wined3d_volume *volume, struct wined3d_context *context, UINT level, BOOL srgb_mode) { const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_format *format = volume->resource.format; TRACE("volume %p, context %p, level %u, srgb %#x, format %s (%#x).\n", volume, context, level, srgb_mode, debug_d3dformat(format->id), format->id); volume_bind_and_dirtify(volume, context); ENTER_GL(); GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, level, format->glInternal, volume->resource.width, volume->resource.height, volume->resource.depth, 0, format->glFormat, format->glType, volume->resource.allocatedMemory)); checkGLcall("glTexImage3D"); LEAVE_GL(); /* When adding code releasing volume->resource.allocatedMemory to save * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by * default if supported(GL_APPLE_client_storage). Thus do not release * volume->resource.allocatedMemory if GL_APPLE_client_storage is * supported. */ }
static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) { IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; struct wined3d_context *context; RECT src_rect, dst_rect; BOOL render_to_fbo; unsigned int sync; int retval; #ifdef VBOX_WITH_WDDM /* quickly sort out invalid swapchains */ if (!This->hDC) { WARN("Invalid swapchain"); return WINED3D_OK; } #endif IWineD3DSwapChain_SetDestWindowOverride(iface, hDestWindowOverride); context = context_acquire(This->device, This->backBuffer[0], CTXUSAGE_RESOURCELOAD); if (!context->valid) { context_release(context); WARN("Invalid context, skipping present.\n"); return WINED3D_OK; } /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ if (This->device->bCursorVisible && This->device->cursorTexture) { IWineD3DSurfaceImpl cursor; RECT destRect = { This->device->xScreenSpace - This->device->xHotSpot, This->device->yScreenSpace - This->device->yHotSpot, This->device->xScreenSpace + This->device->cursorWidth - This->device->xHotSpot, This->device->yScreenSpace + This->device->cursorHeight - This->device->yHotSpot, }; TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor); /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by * the application because we are only supposed to copy the information out. Using a fake surface * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code. */ memset(&cursor, 0, sizeof(cursor)); cursor.lpVtbl = &IWineD3DSurface_Vtbl; cursor.resource.ref = 1; cursor.resource.device = This->device; cursor.resource.pool = WINED3DPOOL_SCRATCH; cursor.resource.format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, context->gl_info); cursor.resource.resourceType = WINED3DRTYPE_SURFACE; cursor.texture_name = This->device->cursorTexture; cursor.texture_target = GL_TEXTURE_2D; cursor.texture_level = 0; cursor.currentDesc.Width = This->device->cursorWidth; cursor.currentDesc.Height = This->device->cursorHeight; /* The cursor must have pow2 sizes */ cursor.pow2Width = cursor.currentDesc.Width; cursor.pow2Height = cursor.currentDesc.Height; /* The surface is in the texture */ cursor.Flags |= SFLAG_INTEXTURE; /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0, * which is exactly what we want :-) */ if (This->presentParms.Windowed) { #ifdef VBOX_WITH_WDDM /* @todo: can we actualy be here? */ #endif MapWindowPoints(NULL, This->win_handle, (LPPOINT)&destRect, 2); } IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *)&cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3DTEXF_POINT); } if (This->device->logo_surface) { /* Blit the logo into the upper left corner of the drawable. */ IWineD3DSurface_BltFast(This->backBuffer[0], 0, 0, This->device->logo_surface, NULL, WINEDDBLTFAST_SRCCOLORKEY); } #ifdef VBOX_WITH_WDDM TRACE("Presenting HDC %p.\n", context->currentSwapchain->hDC); #else TRACE("Presenting HDC %p.\n", context->hdc); #endif render_to_fbo = This->render_to_fbo; if (pSourceRect) { src_rect = *pSourceRect; if (!render_to_fbo && (src_rect.left || src_rect.top || src_rect.right != This->presentParms.BackBufferWidth || src_rect.bottom != This->presentParms.BackBufferHeight)) { render_to_fbo = TRUE; } } else { src_rect.left = 0; src_rect.top = 0; src_rect.right = This->presentParms.BackBufferWidth; src_rect.bottom = This->presentParms.BackBufferHeight; } if (pDestRect) dst_rect = *pDestRect; #ifndef VBOX_WITH_WDDM else GetClientRect(This->win_handle, &dst_rect); if (!render_to_fbo && (dst_rect.left || dst_rect.top || dst_rect.right != This->presentParms.BackBufferWidth || dst_rect.bottom != This->presentParms.BackBufferHeight)) { render_to_fbo = TRUE; } #else else { dst_rect.left = 0; dst_rect.top = 0; dst_rect.right = This->presentParms.BackBufferWidth; dst_rect.bottom = This->presentParms.BackBufferHeight; } #endif /* Rendering to a window of different size, presenting partial rectangles, * or rendering to a different window needs help from FBO_blit or a textured * draw. Render the swapchain to a FBO in the future. * * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve * all these issues - this fails if the window is smaller than the backbuffer. */ if (!This->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { IWineD3DSurface_LoadLocation(This->backBuffer[0], SFLAG_INTEXTURE, NULL); IWineD3DSurface_ModifyLocation(This->backBuffer[0], SFLAG_INDRAWABLE, FALSE); This->render_to_fbo = TRUE; /* Force the context manager to update the render target configuration next draw. */ context->current_rt = NULL; } if(This->render_to_fbo) { /* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer- * window size mismatch is impossible(fullscreen) and src and dst rectangles are * not allowed(they need the COPY swapeffect) * * The DISCARD swap effect is ok as well since any backbuffer content is allowed after * the swap */ if(This->presentParms.SwapEffect == WINED3DSWAPEFFECT_FLIP ) { FIXME("Render-to-fbo with WINED3DSWAPEFFECT_FLIP\n"); } swapchain_blit(This, context, &src_rect, &dst_rect); } #ifdef VBOX_WITH_WDDM if (This->device->numContexts > 1) wglFinish(); #else if (This->num_contexts > 1) wglFinish(); #endif #if defined(VBOX_WITH_WDDM) && defined(DEBUG) { HWND wnd = WindowFromDC(context->currentSwapchain->hDC); Assert(wnd == context->currentSwapchain->win_handle); } #endif #ifdef VBOX_WITH_WDDM /* We're directly using wglMakeCurrent calls skipping GDI layer, which causes GDI SwapBuffers to fail trying to * call glFinish, which doesn't have any context set. So we use wglSwapLayerBuffers directly as well. */ pwglSwapLayerBuffers(context->currentSwapchain->hDC, WGL_SWAP_MAIN_PLANE); #else # ifdef VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT pwglSwapLayerBuffers(context->hdc, WGL_SWAP_MAIN_PLANE); # else SwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */ # endif #endif TRACE("SwapBuffers called, Starting new frame\n"); /* FPS support */ if (TRACE_ON(fps)) { DWORD time = GetTickCount(); This->frames++; /* every 1.5 seconds */ if (time - This->prev_time > 1500) { TRACE_(fps)("%p @ approx %.2ffps\n", This, 1000.0*This->frames/(time - This->prev_time)); This->prev_time = time; This->frames = 0; } } #if defined(FRAME_DEBUGGING) { if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) { if (!isOn) { isOn = TRUE; FIXME("Enabling D3D Trace\n"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1); #if defined(SHOW_FRAME_MAKEUP) FIXME("Singe Frame snapshots Starting\n"); isDumpingFrames = TRUE; ENTER_GL(); glClear(GL_COLOR_BUFFER_BIT); LEAVE_GL(); #endif #if defined(SINGLE_FRAME_DEBUGGING) } else { #if defined(SHOW_FRAME_MAKEUP) FIXME("Singe Frame snapshots Finishing\n"); isDumpingFrames = FALSE; #endif FIXME("Singe Frame trace complete\n"); DeleteFileA("C:\\D3DTRACE"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); #endif } } else { if (isOn) { isOn = FALSE; #if defined(SHOW_FRAME_MAKEUP) FIXME("Single Frame snapshots Finishing\n"); isDumpingFrames = FALSE; #endif FIXME("Disabling D3D Trace\n"); __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); } } } #endif /* This is disabled, but the code left in for debug purposes. * * Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip, * we can clear it with some ugly color to make bad drawing visible and ease debugging. * The Debug runtime does the same on Windows. However, a few games do not redraw the * screen properly, like Max Payne 2, which leaves a few pixels undefined. * * Tests show that the content of the back buffer after a discard flip is indeed not * reliable, so no game can depend on the exact content. However, it resembles the * old contents in some way, for example by showing fragments at other locations. In * general, the color theme is still intact. So Max payne, which draws rather dark scenes * gets a dark background image. If we clear it with a bright ugly color, the game's * bug shows up much more than it does on Windows, and the players see single pixels * with wrong colors. * (The Max Payne bug has been confirmed on Windows with the debug runtime) */ if (FALSE && This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) { TRACE("Clearing the color buffer with cyan color\n"); IWineD3DDevice_Clear((IWineD3DDevice *)This->device, 0, NULL, WINED3DCLEAR_TARGET, 0xff00ffff, 1.0f, 0); } if(!This->render_to_fbo && ( ((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM || ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) ) { /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying * Doesn't work with render_to_fbo because we're not flipping */ IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer; IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0]; if(front->resource.size == back->resource.size) { DWORD fbflags; flip_surface(front, back); /* Tell the front buffer surface that is has been modified. However, * the other locations were preserved during that, so keep the flags. * This serves to update the emulated overlay, if any */ fbflags = front->Flags; IWineD3DSurface_ModifyLocation(This->frontBuffer, SFLAG_INDRAWABLE, TRUE); front->Flags = fbflags; } else { IWineD3DSurface_ModifyLocation((IWineD3DSurface *) front, SFLAG_INDRAWABLE, TRUE); IWineD3DSurface_ModifyLocation((IWineD3DSurface *) back, SFLAG_INDRAWABLE, TRUE); } } else { IWineD3DSurface_ModifyLocation(This->frontBuffer, SFLAG_INDRAWABLE, TRUE); /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM * and INTEXTURE copies can keep their old content if they have any defined content. * If the swapeffect is COPY, the content remains the same. If it is FLIP however, * the texture / sysmem copy needs to be reloaded from the drawable */ if(This->presentParms.SwapEffect == WINED3DSWAPEFFECT_FLIP) { IWineD3DSurface_ModifyLocation(This->backBuffer[0], SFLAG_INDRAWABLE, TRUE); } } if (This->device->stencilBufferTarget) { if (This->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL || ((IWineD3DSurfaceImpl *)This->device->stencilBufferTarget)->Flags & SFLAG_DISCARD) { surface_modify_ds_location(This->device->stencilBufferTarget, SFLAG_DS_DISCARDED); } } if (This->presentParms.PresentationInterval != WINED3DPRESENT_INTERVAL_IMMEDIATE && context->gl_info->supported[SGI_VIDEO_SYNC]) { retval = GL_EXTCALL(glXGetVideoSyncSGI(&sync)); if(retval != 0) { ERR("glXGetVideoSyncSGI failed(retval = %d\n", retval); } switch(This->presentParms.PresentationInterval) { case WINED3DPRESENT_INTERVAL_DEFAULT: case WINED3DPRESENT_INTERVAL_ONE: if(sync <= This->vSyncCounter) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(1, 0, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_TWO: if(sync <= This->vSyncCounter + 1) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(2, This->vSyncCounter & 0x1, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_THREE: if(sync <= This->vSyncCounter + 2) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(3, This->vSyncCounter % 0x3, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; case WINED3DPRESENT_INTERVAL_FOUR: if(sync <= This->vSyncCounter + 3) { retval = GL_EXTCALL(glXWaitVideoSyncSGI(4, This->vSyncCounter & 0x3, &This->vSyncCounter)); } else { This->vSyncCounter = sync; } break; default: FIXME("Unknown presentation interval %08x\n", This->presentParms.PresentationInterval); } } context_release(context); TRACE("returning\n"); return WINED3D_OK; }
/* A GL context is provided by the caller */ static void swapchain_blit(IWineD3DSwapChainImpl *This, struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect) { IWineD3DDeviceImpl *device = This->device; IWineD3DSurfaceImpl *backbuffer = ((IWineD3DSurfaceImpl *) This->backBuffer[0]); UINT src_w = src_rect->right - src_rect->left; UINT src_h = src_rect->bottom - src_rect->top; GLenum gl_filter; const struct wined3d_gl_info *gl_info = context->gl_info; TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n", This, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect)); if (src_w == dst_rect->right - dst_rect->left && src_h == dst_rect->bottom - dst_rect->top) gl_filter = GL_NEAREST; else gl_filter = GL_LINEAR; if (0 && gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format_desc->color_fixup)) { ENTER_GL(); context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo); context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, backbuffer); context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE); context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL); context_set_draw_buffer(context, GL_BACK); glDisable(GL_SCISSOR_TEST); IWineD3DDeviceImpl_MarkStateDirty(This->device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); /* Note that the texture is upside down */ gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, dst_rect->left, dst_rect->bottom, dst_rect->right, dst_rect->top, GL_COLOR_BUFFER_BIT, gl_filter); checkGLcall("Swapchain present blit(EXT_framebuffer_blit)\n"); LEAVE_GL(); } else { struct wined3d_context *context2; float tex_left = src_rect->left; float tex_top = src_rect->top; float tex_right = src_rect->right; float tex_bottom = src_rect->bottom; context2 = context_acquire(This->device, This->backBuffer[0], CTXUSAGE_BLIT); if(backbuffer->Flags & SFLAG_NORMCOORD) { tex_left /= src_w; tex_right /= src_w; tex_top /= src_h; tex_bottom /= src_h; } if (is_complex_fixup(backbuffer->resource.format_desc->color_fixup)) gl_filter = GL_NEAREST; ENTER_GL(); context_bind_fbo(context2, GL_DRAW_FRAMEBUFFER, NULL); /* Set up the texture. The surface is not in a IWineD3D*Texture container, * so there are no d3d texture settings to dirtify */ device->blitter->set_shader((IWineD3DDevice *) device, backbuffer); glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, gl_filter); glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, gl_filter); context_set_draw_buffer(context, GL_BACK); /* Set the viewport to the destination rectandle, disable any projection * transformation set up by CTXUSAGE_BLIT, and draw a (-1,-1)-(1,1) quad. * * Back up viewport and matrix to avoid breaking last_was_blit * * Note that CTXUSAGE_BLIT set up viewport and ortho to match the surface * size - we want the GL drawable(=window) size. */ glPushAttrib(GL_VIEWPORT_BIT); glViewport(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glBegin(GL_QUADS); /* bottom left */ glTexCoord2f(tex_left, tex_bottom); glVertex2i(-1, -1); /* top left */ glTexCoord2f(tex_left, tex_top); glVertex2i(-1, 1); /* top right */ glTexCoord2f(tex_right, tex_top); glVertex2i(1, 1); /* bottom right */ glTexCoord2f(tex_right, tex_bottom); glVertex2i(1, -1); glEnd(); glPopMatrix(); glPopAttrib(); device->blitter->unset_shader((IWineD3DDevice *) device); checkGLcall("Swapchain present blit(manual)\n"); LEAVE_GL(); context_release(context2); } }
/* Routine common to the draw primitive and draw indexed primitive routines */ void drawPrimitive(IWineD3DDeviceImpl *device, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData) { const struct wined3d_state *state = &device->stateBlock->state; struct wined3d_context *context; unsigned int i; if (!index_count) return; if (state->render_states[WINED3DRS_COLORWRITEENABLE]) { /* Invalidate the back buffer memory so LockRect will read it the next time */ for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { IWineD3DSurfaceImpl *target = device->render_targets[i]; if (target) { surface_load_location(target, SFLAG_INDRAWABLE, NULL); surface_modify_location(target, SFLAG_INDRAWABLE, TRUE); } } } /* Signals other modules that a drawing is in progress and the stateblock finalized */ device->isInDraw = TRUE; context = context_acquire(device, device->render_targets[0]); if (!context->valid) { context_release(context); WARN("Invalid context, skipping draw.\n"); return; } context_apply_draw_state(context, device); if (device->depth_stencil) { /* Note that this depends on the context_acquire() call above to set * context->render_offscreen properly. We don't currently take the * Z-compare function into account, but we could skip loading the * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note * that we never copy the stencil data.*/ DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN; if (state->render_states[WINED3DRS_ZWRITEENABLE] || state->render_states[WINED3DRS_ZENABLE]) { IWineD3DSurfaceImpl *ds = device->depth_stencil; RECT current_rect, draw_rect, r; if (location == SFLAG_DS_ONSCREEN && ds != device->onscreen_depth_stencil) device_switch_onscreen_ds(device, context, ds); if (ds->flags & location) SetRect(¤t_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy); else SetRectEmpty(¤t_rect); device_get_draw_rect(device, &draw_rect); IntersectRect(&r, &draw_rect, ¤t_rect); if (!EqualRect(&r, &draw_rect)) surface_load_ds_location(ds, context, location); if (state->render_states[WINED3DRS_ZWRITEENABLE]) { surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy); surface_modify_location(ds, SFLAG_INDRAWABLE, TRUE); } } } if ((!context->gl_info->supported[WINED3D_GL_VERSION_2_0] || (!glPointParameteri && !context->gl_info->supported[NV_POINT_SPRITE])) && context->render_offscreen && state->render_states[WINED3DRS_POINTSPRITEENABLE] && state->gl_primitive_type == GL_POINTS) { FIXME("Point sprite coordinate origin switching not supported.\n"); } /* Ok, we will be updating the screen from here onwards so grab the lock */ ENTER_GL(); { GLenum glPrimType = state->gl_primitive_type; BOOL emulation = FALSE; const struct wined3d_stream_info *stream_info = &device->strided_streams; struct wined3d_stream_info stridedlcl; if (!use_vs(state)) { if (!stream_info->position_transformed && context->num_untracked_materials && state->render_states[WINED3DRS_LIGHTING]) { static BOOL warned; if (!warned) { FIXME("Using software emulation because not all material properties could be tracked\n"); warned = TRUE; } else { TRACE("Using software emulation because not all material properties could be tracked\n"); } emulation = TRUE; } else if (context->fog_coord && state->render_states[WINED3DRS_FOGENABLE]) { /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte * to a float in the vertex buffer */ static BOOL warned; if (!warned) { FIXME("Using software emulation because manual fog coordinates are provided\n"); warned = TRUE; } else { TRACE("Using software emulation because manual fog coordinates are provided\n"); } emulation = TRUE; } if(emulation) { stream_info = &stridedlcl; memcpy(&stridedlcl, &device->strided_streams, sizeof(stridedlcl)); remove_vbos(context->gl_info, state, &stridedlcl); } } if (device->useDrawStridedSlow || emulation) { /* Immediate mode drawing */ if (use_vs(state)) { static BOOL warned; if (!warned) { FIXME("Using immediate mode with vertex shaders for half float emulation\n"); warned = TRUE; } else { TRACE("Using immediate mode with vertex shaders for half float emulation\n"); } drawStridedSlowVs(context->gl_info, state, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedSlow(device, context, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } } else if (device->instancedDraw) { /* Instancing emulation with mixing immediate mode and arrays */ drawStridedInstanced(context->gl_info, state, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedFast(glPrimType, index_count, idxSize, idxData, StartIdx); } } /* Finished updating the screen, restore lock */ LEAVE_GL(); for(i = 0; i < device->num_buffer_queries; ++i) { wined3d_event_query_issue(device->buffer_queries[i], device); } if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ context_release(context); TRACE("Done all gl drawing\n"); /* Control goes back to the device, stateblock values may change again */ device->isInDraw = FALSE; }
/*********************************************************************** * wglUseFontOutlines_common */ static BOOL wglUseFontOutlines_common(HDC hdc, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf, BOOL unicode) { UINT glyph; const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; GLUtesselator *tess; LOGFONTW lf; HFONT old_font, unscaled_font; UINT em_size = 1024; RECT rc; TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count, listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A"); if (!load_libglu()) { ERR("libGLU is required for this function but isn't loaded\n"); return FALSE; } ENTER_GL(); tess = pgluNewTess(); if(tess) { pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex); pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin); pgluTessCallback(tess, GLU_TESS_END, tess_callback_end); } LEAVE_GL(); if(!tess) return FALSE; GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf); rc.left = rc.right = rc.bottom = 0; rc.top = em_size; DPtoLP(hdc, (POINT*)&rc, 2); lf.lfHeight = -abs(rc.top - rc.bottom); lf.lfOrientation = lf.lfEscapement = 0; unscaled_font = CreateFontIndirectW(&lf); old_font = SelectObject(hdc, unscaled_font); for (glyph = first; glyph < first + count; glyph++) { DWORD needed; GLYPHMETRICS gm; BYTE *buf; TTPOLYGONHEADER *pph; TTPOLYCURVE *ppc; GLdouble *vertices; if(unicode) needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity); else needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity); if(needed == GDI_ERROR) goto error; buf = HeapAlloc(GetProcessHeap(), 0, needed); vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble)); if(unicode) GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity); else GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity); TRACE("glyph %d\n", glyph); if(lpgmf) { lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size; lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size; lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size; lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size; lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size; lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size; TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY, lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); lpgmf++; } ENTER_GL(); glNewList(listBase++, GL_COMPILE); pgluTessBeginPolygon(tess, NULL); pph = (TTPOLYGONHEADER*)buf; while((BYTE*)pph < buf + needed) { TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value); pgluTessBeginContour(tess); fixed_to_double(pph->pfxStart, em_size, vertices); pgluTessVertex(tess, vertices, vertices); vertices += 3; ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph)); while((char*)ppc < (char*)pph + pph->cb) { int i; switch(ppc->wType) { case TT_PRIM_LINE: for(i = 0; i < ppc->cpfx; i++) { TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value); fixed_to_double(ppc->apfx[i], em_size, vertices); pgluTessVertex(tess, vertices, vertices); vertices += 3; } break; case TT_PRIM_QSPLINE: for(i = 0; i < ppc->cpfx/2; i++) { /* FIXME just connecting the control points for now */ TRACE("\t\tcurve %d,%d %d,%d\n", ppc->apfx[i * 2].x.value, ppc->apfx[i * 3].y.value, ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value); fixed_to_double(ppc->apfx[i * 2], em_size, vertices); pgluTessVertex(tess, vertices, vertices); vertices += 3; fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); pgluTessVertex(tess, vertices, vertices); vertices += 3; } break; default: ERR("\t\tcurve type = %d\n", ppc->wType); pgluTessEndContour(tess); goto error_in_list; } ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) + (ppc->cpfx - 1) * sizeof(POINTFX)); } pgluTessEndContour(tess); pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb); } error_in_list: pgluTessEndPolygon(tess); glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0); glEndList(); LEAVE_GL(); HeapFree(GetProcessHeap(), 0, buf); HeapFree(GetProcessHeap(), 0, vertices); } error: DeleteObject(SelectObject(hdc, old_font)); pgluDeleteTess(tess); return TRUE; }
static HRESULT WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags) { IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; IWineD3DDeviceImpl *device = This->device; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; if (gl_info->supported[ARB_OCCLUSION_QUERY]) { struct wined3d_occlusion_query *query = This->extendedData; struct wined3d_context *context; /* This is allowed according to msdn and our tests. Reset the query and restart */ if (dwIssueFlags & WINED3DISSUE_BEGIN) { if (This->state == QUERY_BUILDING) { if (query->context->tid != GetCurrentThreadId()) { FIXME("Wrong thread, can't restart query.\n"); context_free_occlusion_query(query); context = context_acquire(This->device, NULL); context_alloc_occlusion_query(context, query); } else { context = context_acquire(This->device, query->context->current_rt); ENTER_GL(); GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB)); checkGLcall("glEndQuery()"); LEAVE_GL(); } } else { if (query->context) context_free_occlusion_query(query); context = context_acquire(This->device, NULL); context_alloc_occlusion_query(context, query); } ENTER_GL(); GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id)); checkGLcall("glBeginQuery()"); LEAVE_GL(); context_release(context); } if (dwIssueFlags & WINED3DISSUE_END) { /* Msdn says _END on a non-building occlusion query returns an error, but * our tests show that it returns OK. But OpenGL doesn't like it, so avoid * generating an error */ if (This->state == QUERY_BUILDING) { if (query->context->tid != GetCurrentThreadId()) { FIXME("Wrong thread, can't end query.\n"); } else { context = context_acquire(This->device, query->context->current_rt); ENTER_GL(); GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB)); checkGLcall("glEndQuery()"); LEAVE_GL(); context_release(context); } } } } else { FIXME("(%p) : Occlusion queries not supported\n", This); } if(dwIssueFlags & WINED3DISSUE_BEGIN) { This->state = QUERY_BUILDING; } else { This->state = QUERY_SIGNALLED; } return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */ }
/* Context activation is done by the caller. */ static HRESULT wined3d_texture_bind(struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info, BOOL srgb, BOOL *set_surface_desc) { struct gl_texture *gl_tex; BOOL new_texture = FALSE; HRESULT hr = WINED3D_OK; GLenum target; TRACE("texture %p, srgb %#x, set_surface_desc %p.\n", texture, srgb, set_surface_desc); /* sRGB mode cache for preload() calls outside drawprim. */ if (srgb) texture->flags |= WINED3D_TEXTURE_IS_SRGB; else texture->flags &= ~WINED3D_TEXTURE_IS_SRGB; gl_tex = wined3d_texture_get_gl_texture(texture, gl_info, srgb); target = texture->target; ENTER_GL(); /* Generate a texture name if we don't already have one. */ if (!gl_tex->name) { *set_surface_desc = TRUE; glGenTextures(1, &gl_tex->name); checkGLcall("glGenTextures"); TRACE("Generated texture %d.\n", gl_tex->name); if (texture->resource.pool == WINED3DPOOL_DEFAULT) { /* Tell OpenGL to try and keep this texture in video ram (well mostly). */ GLclampf tmp = 0.9f; glPrioritizeTextures(1, &gl_tex->name, &tmp); } /* Initialise the state of the texture object to the OpenGL defaults, * not the D3D defaults. */ gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = 0; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = 1; if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = TRUE; else gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = srgb; gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE; wined3d_texture_set_dirty(texture, TRUE); new_texture = TRUE; if (texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) { /* This means double binding the texture at creation, but keeps * the code simpler all in all, and the run-time path free from * additional checks. */ glBindTexture(target, gl_tex->name); checkGLcall("glBindTexture"); glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)"); } } else { *set_surface_desc = FALSE; } if (gl_tex->name) { glBindTexture(target, gl_tex->name); checkGLcall("glBindTexture"); if (new_texture) { /* For a new texture we have to set the texture levels after * binding the texture. Beware that texture rectangles do not * support mipmapping, but set the maxmiplevel if we're relying * on the partial GL_ARB_texture_non_power_of_two emulation with * texture rectangles. (I.e., do not care about cond_np2 here, * just look for GL_TEXTURE_RECTANGLE_ARB.) */ if (target != GL_TEXTURE_RECTANGLE_ARB) { TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture->level_count - 1); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1); checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)"); } if (target == GL_TEXTURE_CUBE_MAP_ARB) { /* Cubemaps are always set to clamp, regardless of the sampler state. */ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } } } else { ERR("This texture doesn't have an OpenGL texture assigned to it.\n"); hr = WINED3DERR_INVALIDCALL; } LEAVE_GL(); return hr; }
/* Routine common to the draw primitive and draw indexed primitive routines */ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DSurfaceImpl *target; struct wined3d_context *context; unsigned int i; if (!index_count) return; if (This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE]) { /* Invalidate the back buffer memory so LockRect will read it the next time */ for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i) { target = (IWineD3DSurfaceImpl *)This->render_targets[i]; if (target) { IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL); IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE); } } } /* Signals other modules that a drawing is in progress and the stateblock finalized */ This->isInDraw = TRUE; context = context_acquire(This, This->render_targets[0], CTXUSAGE_DRAWPRIM); if (!context->valid) { context_release(context); WARN("Invalid context, skipping draw.\n"); return; } #if defined(VBOX_WITH_WDDM) DBGL_CHECK_DRAWPRIM(context->gl_info, This); #endif if (This->stencilBufferTarget) { /* Note that this depends on the context_acquire() call above to set * This->render_offscreen properly. We don't currently take the * Z-compare function into account, but we could skip loading the * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note * that we never copy the stencil data.*/ DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN; if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE] || This->stateBlock->renderState[WINED3DRS_ZENABLE]) surface_load_ds_location(This->stencilBufferTarget, context, location); if (This->stateBlock->renderState[WINED3DRS_ZWRITEENABLE]) surface_modify_ds_location(This->stencilBufferTarget, location); } /* Ok, we will be updating the screen from here onwards so grab the lock */ ENTER_GL(); { GLenum glPrimType = This->stateBlock->gl_primitive_type; BOOL emulation = FALSE; const struct wined3d_stream_info *stream_info = &This->strided_streams; struct wined3d_stream_info stridedlcl; if (!use_vs(This->stateBlock)) { if (!This->strided_streams.position_transformed && context->num_untracked_materials && This->stateBlock->renderState[WINED3DRS_LIGHTING]) { static BOOL warned; if (!warned) { FIXME("Using software emulation because not all material properties could be tracked\n"); warned = TRUE; } else { TRACE("Using software emulation because not all material properties could be tracked\n"); } emulation = TRUE; } else if (context->fog_coord && This->stateBlock->renderState[WINED3DRS_FOGENABLE]) { /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte * to a float in the vertex buffer */ static BOOL warned; if (!warned) { FIXME("Using software emulation because manual fog coordinates are provided\n"); warned = TRUE; } else { TRACE("Using software emulation because manual fog coordinates are provided\n"); } emulation = TRUE; } if(emulation) { stream_info = &stridedlcl; memcpy(&stridedlcl, &This->strided_streams, sizeof(stridedlcl)); remove_vbos(This, &stridedlcl); } } if (This->useDrawStridedSlow || emulation) { /* Immediate mode drawing */ if (use_vs(This->stateBlock)) { static BOOL warned; if (!warned) { FIXME("Using immediate mode with vertex shaders for half float emulation\n"); warned = TRUE; } else { TRACE("Using immediate mode with vertex shaders for half float emulation\n"); } drawStridedSlowVs(iface, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedSlow(iface, context, stream_info, index_count, glPrimType, idxData, idxSize, StartIdx); } } else if(This->instancedDraw) { /* Instancing emulation with mixing immediate mode and arrays */ drawStridedInstanced(iface, &This->strided_streams, index_count, glPrimType, idxData, idxSize, StartIdx); } else { drawStridedFast(iface, glPrimType, index_count, idxSize, idxData, StartIdx); } } /* Finished updating the screen, restore lock */ LEAVE_GL(); for(i = 0; i < This->num_buffer_queries; i++) { wined3d_event_query_issue(This->buffer_queries[i], This); } if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ context_release(context); TRACE("Done all gl drawing\n"); /* Diagnostics */ #ifdef SHOW_FRAME_MAKEUP { static long int primCounter = 0; /* NOTE: set primCounter to the value reported by drawprim before you want to to write frame makeup to /tmp */ if (primCounter >= 0) { WINED3DLOCKED_RECT r; char buffer[80]; IWineD3DSurface_LockRect(This->render_targets[0], &r, NULL, WINED3DLOCK_READONLY); sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter); TRACE("Saving screenshot %s\n", buffer); IWineD3DSurface_SaveSnapshot(This->render_targets[0], buffer); IWineD3DSurface_UnlockRect(This->render_targets[0]); #ifdef SHOW_TEXTURE_MAKEUP { IWineD3DSurface *pSur; int textureNo; for (textureNo = 0; textureNo < MAX_COMBINED_SAMPLERS; ++textureNo) { if (This->stateBlock->textures[textureNo] != NULL) { sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo); TRACE("Saving texture %s\n", buffer); if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) { IWineD3DTexture_GetSurfaceLevel(This->stateBlock->textures[textureNo], 0, &pSur); IWineD3DSurface_SaveSnapshot(pSur, buffer); IWineD3DSurface_Release(pSur); } else { FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo])); } } } } #endif } TRACE("drawprim #%ld\n", primCounter); ++primCounter; } #endif /* Control goes back to the device, stateblock values may change again */ This->isInDraw = FALSE; }
/* Tesselates a high order rectangular patch into single triangles using gl evaluators * * The problem is that OpenGL does not offer a direct way to return the tesselated primitives, * and they can't be sent off for rendering directly either. Tesselating is slow, so we want * to cache the patches in a vertex buffer. But more importantly, gl can't bind generated * attributes to numbered shader attributes, so we have to store them and rebind them as needed * in drawprim. * * To read back, the opengl feedback mode is used. This creates a problem because we want * untransformed, unlit vertices, but feedback runs everything through transform and lighting. * Thus disable lighting and set identity matrices to get unmodified colors and positions. * To overcome clipping find the biggest x, y and z values of the vertices in the patch and scale * them to [-1.0;+1.0] and set the viewport up to scale them back. * * Normals are more tricky: Draw white vertices with 3 directional lights, and calculate the * resulting colors back to the normals. * * NOTE: This function activates a context for blitting, modifies matrices & viewport, but * does not restore it because normally a draw follows immediately afterwards. The caller is * responsible of taking care that either the gl states are restored, or the context activated * for drawing to reset the lastWasBlit flag. */ HRESULT tesselate_rectpatch(IWineD3DDeviceImpl *This, struct WineD3DRectPatch *patch) { unsigned int i, j, num_quads, out_vertex_size, buffer_size, d3d_out_vertex_size; float max_x = 0.0f, max_y = 0.0f, max_z = 0.0f, neg_z = 0.0f; struct wined3d_stream_info stream_info; struct wined3d_stream_info_element *e; struct wined3d_context *context; const BYTE *data; const WINED3DRECTPATCH_INFO *info = &patch->RectPatchInfo; DWORD vtxStride; GLenum feedback_type; GLfloat *feedbuffer; /* Simply activate the context for blitting. This disables all the things we don't want and * takes care of dirtifying. Dirtifying is preferred over pushing / popping, since drawing the * patch (as opposed to normal draws) will most likely need different changes anyway. */ context = context_acquire(This, NULL, CTXUSAGE_BLIT); /* First, locate the position data. This is provided in a vertex buffer in the stateblock. * Beware of vbos */ device_stream_info_from_declaration(This, FALSE, &stream_info, NULL); e = &stream_info.elements[WINED3D_FFP_POSITION]; if (e->buffer_object) { struct wined3d_buffer *vb; vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx]; e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb)); } vtxStride = e->stride; data = e->data + vtxStride * info->Stride * info->StartVertexOffsetHeight + vtxStride * info->StartVertexOffsetWidth; /* Not entirely sure about what happens with transformed vertices */ if (stream_info.position_transformed) FIXME("Transformed position in rectpatch generation\n"); if(vtxStride % sizeof(GLfloat)) { /* glMap2f reads vertex sizes in GLfloats, the d3d stride is in bytes. * I don't see how the stride could not be a multiple of 4, but make sure * to check it */ ERR("Vertex stride is not a multiple of sizeof(GLfloat)\n"); } if(info->Basis != WINED3DBASIS_BEZIER) { FIXME("Basis is %s, how to handle this?\n", debug_d3dbasis(info->Basis)); } if(info->Degree != WINED3DDEGREE_CUBIC) { FIXME("Degree is %s, how to handle this?\n", debug_d3ddegree(info->Degree)); } /* First, get the boundary cube of the input data */ for(j = 0; j < info->Height; j++) { for(i = 0; i < info->Width; i++) { const float *v = (const float *)(data + vtxStride * i + vtxStride * info->Stride * j); if(fabs(v[0]) > max_x) max_x = fabs(v[0]); if(fabs(v[1]) > max_y) max_y = fabs(v[1]); if(fabs(v[2]) > max_z) max_z = fabs(v[2]); if(v[2] < neg_z) neg_z = v[2]; } } /* This needs some improvements in the vertex decl code */ FIXME("Cannot find data to generate. Only generating position and normals\n"); patch->has_normals = TRUE; patch->has_texcoords = FALSE; ENTER_GL(); glMatrixMode(GL_PROJECTION); checkGLcall("glMatrixMode(GL_PROJECTION)"); glLoadIdentity(); checkGLcall("glLoadIndentity()"); glScalef(1.0f / (max_x), 1.0f / (max_y), max_z == 0.0f ? 1.0f : 1.0f / (2.0f * max_z)); glTranslatef(0.0f, 0.0f, 0.5f); checkGLcall("glScalef"); glViewport(-max_x, -max_y, 2 * (max_x), 2 * (max_y)); checkGLcall("glViewport"); /* Some states to take care of. If we're in wireframe opengl will produce lines, and confuse * our feedback buffer parser */ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_FILLMODE)); if(patch->has_normals) { static const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f}; static const GLfloat red[] = {1.0f, 0.0f, 0.0f, 0.0f}; static const GLfloat green[] = {0.0f, 1.0f, 0.0f, 0.0f}; static const GLfloat blue[] = {0.0f, 0.0f, 1.0f, 0.0f}; static const GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f}; glEnable(GL_LIGHTING); checkGLcall("glEnable(GL_LIGHTING)"); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); checkGLcall("glLightModel for MODEL_AMBIENT"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_AMBIENT)); for (i = 3; i < context->gl_info->limits.lights; ++i) { glDisable(GL_LIGHT0 + i); checkGLcall("glDisable(GL_LIGHT0 + i)"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i)); } IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(0)); glLightfv(GL_LIGHT0, GL_DIFFUSE, red); glLightfv(GL_LIGHT0, GL_SPECULAR, black); glLightfv(GL_LIGHT0, GL_AMBIENT, black); glLightfv(GL_LIGHT0, GL_POSITION, red); glEnable(GL_LIGHT0); checkGLcall("Setting up light 1"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(1)); glLightfv(GL_LIGHT1, GL_DIFFUSE, green); glLightfv(GL_LIGHT1, GL_SPECULAR, black); glLightfv(GL_LIGHT1, GL_AMBIENT, black); glLightfv(GL_LIGHT1, GL_POSITION, green); glEnable(GL_LIGHT1); checkGLcall("Setting up light 2"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(2)); glLightfv(GL_LIGHT2, GL_DIFFUSE, blue); glLightfv(GL_LIGHT2, GL_SPECULAR, black); glLightfv(GL_LIGHT2, GL_AMBIENT, black); glLightfv(GL_LIGHT2, GL_POSITION, blue); glEnable(GL_LIGHT2); checkGLcall("Setting up light 3"); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORVERTEX)); glDisable(GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); checkGLcall("Setting up materials"); } /* Enable the needed maps. * GL_MAP2_VERTEX_3 is needed for positional data. * GL_AUTO_NORMAL to generate normals from the position. Do not use GL_MAP2_NORMAL. * GL_MAP2_TEXTURE_COORD_4 for texture coords */ num_quads = ceilf(patch->numSegs[0]) * ceilf(patch->numSegs[1]); out_vertex_size = 3 /* position */; d3d_out_vertex_size = 3; glEnable(GL_MAP2_VERTEX_3); if(patch->has_normals && patch->has_texcoords) { FIXME("Texcoords not handled yet\n"); feedback_type = GL_3D_COLOR_TEXTURE; out_vertex_size += 8; d3d_out_vertex_size += 7; glEnable(GL_AUTO_NORMAL); glEnable(GL_MAP2_TEXTURE_COORD_4); } else if(patch->has_texcoords) { FIXME("Texcoords not handled yet\n"); feedback_type = GL_3D_COLOR_TEXTURE; out_vertex_size += 7; d3d_out_vertex_size += 4; glEnable(GL_MAP2_TEXTURE_COORD_4); } else if(patch->has_normals) { feedback_type = GL_3D_COLOR; out_vertex_size += 4; d3d_out_vertex_size += 3; glEnable(GL_AUTO_NORMAL); } else { feedback_type = GL_3D; } checkGLcall("glEnable vertex attrib generation"); buffer_size = num_quads * out_vertex_size * 2 /* triangle list */ * 3 /* verts per tri */ + 4 * num_quads /* 2 triangle markers per quad + num verts in tri */; feedbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size * sizeof(float) * 8); glMap2f(GL_MAP2_VERTEX_3, 0.0f, 1.0f, vtxStride / sizeof(float), info->Width, 0.0f, 1.0f, info->Stride * vtxStride / sizeof(float), info->Height, (const GLfloat *)data); checkGLcall("glMap2f"); if(patch->has_texcoords) { glMap2f(GL_MAP2_TEXTURE_COORD_4, 0.0f, 1.0f, vtxStride / sizeof(float), info->Width, 0.0f, 1.0f, info->Stride * vtxStride / sizeof(float), info->Height, (const GLfloat *)data); checkGLcall("glMap2f"); } glMapGrid2f(ceilf(patch->numSegs[0]), 0.0f, 1.0f, ceilf(patch->numSegs[1]), 0.0f, 1.0f); checkGLcall("glMapGrid2f"); glFeedbackBuffer(buffer_size * 2, feedback_type, feedbuffer); checkGLcall("glFeedbackBuffer"); glRenderMode(GL_FEEDBACK); glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); checkGLcall("glEvalMesh2"); i = glRenderMode(GL_RENDER); if(i == -1) { LEAVE_GL(); ERR("Feedback failed. Expected %d elements back\n", buffer_size); HeapFree(GetProcessHeap(), 0, feedbuffer); context_release(context); return WINED3DERR_DRIVERINTERNALERROR; } else if(i != buffer_size) { LEAVE_GL(); ERR("Unexpected amount of elements returned. Expected %d, got %d\n", buffer_size, i); HeapFree(GetProcessHeap(), 0, feedbuffer); context_release(context); return WINED3DERR_DRIVERINTERNALERROR; } else { TRACE("Got %d elements as expected\n", i); } HeapFree(GetProcessHeap(), 0, patch->mem); patch->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_quads * 6 * d3d_out_vertex_size * sizeof(float) * 8); i = 0; for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { if(feedbuffer[j] != GL_POLYGON_TOKEN) { ERR("Unexpected token: %f\n", feedbuffer[j]); continue; } if(feedbuffer[j + 1] != 3) { ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); continue; } /* Somehow there are different ideas about back / front facing, so fix up the * vertex order */ patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 2 + 2]; /* x, triangle 2 */ patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 2 + 3]; /* y, triangle 2 */ patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 2 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 3 */ if(patch->has_normals) { patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 2 + 5]; patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 2 + 6]; patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 2 + 7]; } i += d3d_out_vertex_size; patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 1 + 2]; /* x, triangle 2 */ patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 1 + 3]; /* y, triangle 2 */ patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 1 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 2 */ if(patch->has_normals) { patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 1 + 5]; patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 1 + 6]; patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 1 + 7]; } i += d3d_out_vertex_size; patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 0 + 2]; /* x, triangle 1 */ patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 0 + 3]; /* y, triangle 1 */ patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 0 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 1 */ if(patch->has_normals) { patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 0 + 5]; patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 0 + 6]; patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 0 + 7]; } i += d3d_out_vertex_size; } if(patch->has_normals) { /* Now do the same with reverse light directions */ static const GLfloat x[] = {-1.0f, 0.0f, 0.0f, 0.0f}; static const GLfloat y[] = { 0.0f, -1.0f, 0.0f, 0.0f}; static const GLfloat z[] = { 0.0f, 0.0f, -1.0f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, x); glLightfv(GL_LIGHT1, GL_POSITION, y); glLightfv(GL_LIGHT2, GL_POSITION, z); checkGLcall("Setting up reverse light directions"); glRenderMode(GL_FEEDBACK); checkGLcall("glRenderMode(GL_FEEDBACK)"); glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); checkGLcall("glEvalMesh2"); i = glRenderMode(GL_RENDER); checkGLcall("glRenderMode(GL_RENDER)"); i = 0; for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { if(feedbuffer[j] != GL_POLYGON_TOKEN) { ERR("Unexpected token: %f\n", feedbuffer[j]); continue; } if(feedbuffer[j + 1] != 3) { ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); continue; } if(patch->mem[i + 3] == 0.0f) patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 2 + 5]; if(patch->mem[i + 4] == 0.0f) patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 2 + 6]; if(patch->mem[i + 5] == 0.0f) patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 2 + 7]; normalize_normal(patch->mem + i + 3); i += d3d_out_vertex_size; if(patch->mem[i + 3] == 0.0f) patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 1 + 5]; if(patch->mem[i + 4] == 0.0f) patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 1 + 6]; if(patch->mem[i + 5] == 0.0f) patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 1 + 7]; normalize_normal(patch->mem + i + 3); i += d3d_out_vertex_size; if(patch->mem[i + 3] == 0.0f) patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 0 + 5]; if(patch->mem[i + 4] == 0.0f) patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 0 + 6]; if(patch->mem[i + 5] == 0.0f) patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 0 + 7]; normalize_normal(patch->mem + i + 3); i += d3d_out_vertex_size; } } glDisable(GL_MAP2_VERTEX_3); glDisable(GL_AUTO_NORMAL); glDisable(GL_MAP2_NORMAL); glDisable(GL_MAP2_TEXTURE_COORD_4); checkGLcall("glDisable vertex attrib generation"); LEAVE_GL(); context_release(context); HeapFree(GetProcessHeap(), 0, feedbuffer); vtxStride = 3 * sizeof(float); if(patch->has_normals) { vtxStride += 3 * sizeof(float); } if(patch->has_texcoords) { vtxStride += 4 * sizeof(float); } memset(&patch->strided, 0, sizeof(patch->strided)); patch->strided.position.format = WINED3DFMT_R32G32B32_FLOAT; patch->strided.position.lpData = (BYTE *) patch->mem; patch->strided.position.dwStride = vtxStride; if(patch->has_normals) { patch->strided.normal.format = WINED3DFMT_R32G32B32_FLOAT; patch->strided.normal.lpData = (BYTE *) patch->mem + 3 * sizeof(float) /* pos */; patch->strided.normal.dwStride = vtxStride; } if(patch->has_texcoords) { patch->strided.texCoords[0].format = WINED3DFMT_R32G32B32A32_FLOAT; patch->strided.texCoords[0].lpData = (BYTE *) patch->mem + 3 * sizeof(float) /* pos */; if(patch->has_normals) { patch->strided.texCoords[0].lpData += 3 * sizeof(float); } patch->strided.texCoords[0].dwStride = vtxStride; } return WINED3D_OK; }
enum wined3d_event_query_result wined3d_event_query_finish(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) { struct wined3d_context *context; const struct wined3d_gl_info *gl_info; enum wined3d_event_query_result ret; TRACE("(%p)\n", query); if (!query->context) { TRACE("Query not started\n"); return WINED3D_EVENT_QUERY_NOT_STARTED; } gl_info = query->context->gl_info; if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC]) { /* A glFinish does not reliably wait for draws in other contexts. The caller has * to find its own way to cope with the thread switch */ WARN("Event query finished from wrong thread\n"); return WINED3D_EVENT_QUERY_WRONG_THREAD; } context = context_acquire(device, query->context->current_rt); ENTER_GL(); if (gl_info->supported[ARB_SYNC]) { GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, ~(GLuint64)0)); checkGLcall("glClientWaitSync"); switch (gl_ret) { case GL_ALREADY_SIGNALED: case GL_CONDITION_SATISFIED: ret = WINED3D_EVENT_QUERY_OK; break; /* We don't expect a timeout for a ~584 year wait */ default: ERR("glClientWaitSync returned %#x.\n", gl_ret); ret = WINED3D_EVENT_QUERY_ERROR; } } else if (context->gl_info->supported[APPLE_FENCE]) { GL_EXTCALL(glFinishFenceAPPLE(query->object.id)); checkGLcall("glFinishFenceAPPLE"); ret = WINED3D_EVENT_QUERY_OK; } else if (context->gl_info->supported[NV_FENCE]) { GL_EXTCALL(glFinishFenceNV(query->object.id)); checkGLcall("glFinishFenceNV"); ret = WINED3D_EVENT_QUERY_OK; } else { ERR("Event query created without GL support\n"); ret = WINED3D_EVENT_QUERY_ERROR; } LEAVE_GL(); context_release(context); return ret; }
/* Context activation is done by the caller. */ HRESULT basetexture_bind(IWineD3DBaseTexture *iface, BOOL srgb, BOOL *set_surface_desc) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; HRESULT hr = WINED3D_OK; GLenum textureDimensions; BOOL isNewTexture = FALSE; struct gl_texture *gl_tex; TRACE("(%p) : About to bind texture\n", This); This->baseTexture.is_srgb = srgb; /* SRGB mode cache for PreLoad calls outside drawprim */ if(srgb) { gl_tex = &This->baseTexture.texture_srgb; } else { gl_tex = &This->baseTexture.texture_rgb; } textureDimensions = This->baseTexture.target; ENTER_GL(); /* Generate a texture name if we don't already have one */ if (!gl_tex->name) { *set_surface_desc = TRUE; glGenTextures(1, &gl_tex->name); checkGLcall("glGenTextures"); TRACE("Generated texture %d\n", gl_tex->name); if (This->resource.pool == WINED3DPOOL_DEFAULT) { /* Tell opengl to try and keep this texture in video ram (well mostly) */ GLclampf tmp; tmp = 0.9f; glPrioritizeTextures(1, &gl_tex->name, &tmp); } /* Initialise the state of the texture object to the openGL defaults, not the directx defaults */ gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = 0; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = 1; gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = 0; gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE; IWineD3DBaseTexture_SetDirty(iface, TRUE); isNewTexture = TRUE; if(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) { /* This means double binding the texture at creation, but keeps the code simpler all * in all, and the run-time path free from additional checks */ glBindTexture(textureDimensions, gl_tex->name); checkGLcall("glBindTexture"); glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)"); } } else { *set_surface_desc = FALSE; } /* Bind the texture */ if (gl_tex->name) { glBindTexture(textureDimensions, gl_tex->name); checkGLcall("glBindTexture"); if (isNewTexture) { /* For a new texture we have to set the textures levels after binding the texture. * In theory this is all we should ever have to do, but because ATI's drivers are broken, we * also need to set the texture dimensions before the texture is set * Beware that texture rectangles do not support mipmapping, but set the maxmiplevel if we're * relying on the partial GL_ARB_texture_non_power_of_two emulation with texture rectangles * (ie, do not care for cond_np2 here, just look for GL_TEXTURE_RECTANGLE_ARB) */ if (textureDimensions != GL_TEXTURE_RECTANGLE_ARB) { TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", This->baseTexture.level_count - 1); glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.level_count - 1); checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.level_count)"); } if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) { /* Cubemaps are always set to clamp, regardless of the sampler state. */ glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } } } else { /* this only happened if we've run out of openGL textures */ WARN("This texture doesn't have an openGL texture assigned to it\n"); hr = WINED3DERR_INVALIDCALL; } LEAVE_GL(); return hr; }
static HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) { IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface; struct wined3d_occlusion_query *query = This->extendedData; IWineD3DDeviceImpl *device = This->device; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; struct wined3d_context *context; DWORD* data = pData; GLuint available; GLuint samples; HRESULT res; TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags); if (!query->context) This->state = QUERY_CREATED; if (This->state == QUERY_CREATED) { /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */ TRACE("Query wasn't yet started, returning S_OK\n"); if(data) *data = 0; return S_OK; } if (This->state == QUERY_BUILDING) { /* Msdn says this returns an error, but our tests show that S_FALSE is returned */ TRACE("Query is building, returning S_FALSE\n"); return S_FALSE; } if (!gl_info->supported[ARB_OCCLUSION_QUERY]) { WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This); *data = 1; return S_OK; } if (query->context->tid != GetCurrentThreadId()) { FIXME("%p Wrong thread, returning 1.\n", This); *data = 1; return S_OK; } context = context_acquire(This->device, query->context->current_rt); ENTER_GL(); GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available)); checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)"); TRACE("(%p) : available %d.\n", This, available); if (available) { if (data) { GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples)); checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)"); TRACE("(%p) : Returning %d samples.\n", This, samples); *data = samples; } res = S_OK; } else { res = S_FALSE; } LEAVE_GL(); context_release(context); return res; }
/* A GL context is provided by the caller */ static void swapchain_blit(const struct wined3d_swapchain *swapchain, struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect) { struct wined3d_surface *backbuffer = swapchain->back_buffers[0]; UINT src_w = src_rect->right - src_rect->left; UINT src_h = src_rect->bottom - src_rect->top; GLenum gl_filter; const struct wined3d_gl_info *gl_info = context->gl_info; RECT win_rect; UINT win_h; TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n", swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect)); if (src_w == dst_rect->right - dst_rect->left && src_h == dst_rect->bottom - dst_rect->top) gl_filter = GL_NEAREST; else gl_filter = GL_LINEAR; GetClientRect(swapchain->win_handle, &win_rect); win_h = win_rect.bottom - win_rect.top; if (gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format->color_fixup)) { DWORD location = SFLAG_INTEXTURE; if (backbuffer->resource.multisample_type) { location = SFLAG_INRB_RESOLVED; surface_load_location(backbuffer, location, NULL); } ENTER_GL(); context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, backbuffer, NULL, location); glReadBuffer(GL_COLOR_ATTACHMENT0); context_check_fbo_status(context, GL_READ_FRAMEBUFFER); context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE); context_set_draw_buffer(context, GL_BACK); context_invalidate_state(context, STATE_FRAMEBUFFER); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE)); context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1)); context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2)); context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3)); glDisable(GL_SCISSOR_TEST); context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE)); /* Note that the texture is upside down */ gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, dst_rect->left, win_h - dst_rect->top, dst_rect->right, win_h - dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter); checkGLcall("Swapchain present blit(EXT_framebuffer_blit)\n"); LEAVE_GL(); } else { struct wined3d_device *device = swapchain->device; struct wined3d_context *context2; float tex_left = src_rect->left; float tex_top = src_rect->top; float tex_right = src_rect->right; float tex_bottom = src_rect->bottom; context2 = context_acquire(device, swapchain->back_buffers[0]); context_apply_blit_state(context2, device); if (backbuffer->flags & SFLAG_NORMCOORD) { tex_left /= src_w; tex_right /= src_w; tex_top /= src_h; tex_bottom /= src_h; } if (is_complex_fixup(backbuffer->resource.format->color_fixup)) gl_filter = GL_NEAREST; ENTER_GL(); context_apply_fbo_state_blit(context2, GL_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE); /* Set up the texture. The surface is not in a wined3d_texture * container, so there are no D3D texture settings to dirtify. */ device->blitter->set_shader(device->blit_priv, context2, backbuffer); glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, gl_filter); glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, gl_filter); context_set_draw_buffer(context, GL_BACK); /* Set the viewport to the destination rectandle, disable any projection * transformation set up by context_apply_blit_state(), and draw a * (-1,-1)-(1,1) quad. * * Back up viewport and matrix to avoid breaking last_was_blit * * Note that context_apply_blit_state() set up viewport and ortho to * match the surface size - we want the GL drawable(=window) size. */ glPushAttrib(GL_VIEWPORT_BIT); glViewport(dst_rect->left, win_h - dst_rect->bottom, dst_rect->right, win_h - dst_rect->top); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glBegin(GL_QUADS); /* bottom left */ glTexCoord2f(tex_left, tex_bottom); glVertex2i(-1, -1); /* top left */ glTexCoord2f(tex_left, tex_top); glVertex2i(-1, 1); /* top right */ glTexCoord2f(tex_right, tex_top); glVertex2i(1, 1); /* bottom right */ glTexCoord2f(tex_right, tex_bottom); glVertex2i(1, -1); glEnd(); glPopMatrix(); glPopAttrib(); device->blitter->unset_shader(context->gl_info); checkGLcall("Swapchain present blit(manual)\n"); LEAVE_GL(); context_release(context2); } }
enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) { struct wined3d_context *context; const struct wined3d_gl_info *gl_info; enum wined3d_event_query_result ret; BOOL fence_result; TRACE("(%p) : device %p\n", query, device); if (!query->context) { TRACE("Query not started\n"); return WINED3D_EVENT_QUERY_NOT_STARTED; } if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId()) { WARN("Event query tested from wrong thread\n"); return WINED3D_EVENT_QUERY_WRONG_THREAD; } context = context_acquire(device, query->context->current_rt); gl_info = context->gl_info; ENTER_GL(); if (gl_info->supported[ARB_SYNC]) { GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, 0)); checkGLcall("glClientWaitSync"); switch (gl_ret) { case GL_ALREADY_SIGNALED: case GL_CONDITION_SATISFIED: ret = WINED3D_EVENT_QUERY_OK; break; case GL_TIMEOUT_EXPIRED: ret = WINED3D_EVENT_QUERY_WAITING; break; case GL_WAIT_FAILED: default: ERR("glClientWaitSync returned %#x.\n", gl_ret); ret = WINED3D_EVENT_QUERY_ERROR; } } else if (gl_info->supported[APPLE_FENCE]) { fence_result = GL_EXTCALL(glTestFenceAPPLE(query->object.id)); checkGLcall("glTestFenceAPPLE"); if (fence_result) ret = WINED3D_EVENT_QUERY_OK; else ret = WINED3D_EVENT_QUERY_WAITING; } else if (gl_info->supported[NV_FENCE]) { fence_result = GL_EXTCALL(glTestFenceNV(query->object.id)); checkGLcall("glTestFenceNV"); if (fence_result) ret = WINED3D_EVENT_QUERY_OK; else ret = WINED3D_EVENT_QUERY_WAITING; } else { ERR("Event query created despite lack of GL support\n"); ret = WINED3D_EVENT_QUERY_ERROR; } LEAVE_GL(); context_release(context); return ret; }