From 943fb2fb578b9d3d2fcd9c4e72bf465fde8e245d Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Mon, 26 Jul 2010 12:06:32 +0200 Subject: [PATCH] wined3d: Do RGB <=> sRGB transfers using FBO blits. Concept based on a patch by Stefan. --- dlls/wined3d/context.c | 104 ++++++++++++++++++++++----------- dlls/wined3d/device.c | 4 +- dlls/wined3d/surface.c | 47 +++++++++++++++ dlls/wined3d/swapchain.c | 2 +- dlls/wined3d/utils.c | 20 +++++++ dlls/wined3d/wined3d_private.h | 6 +- 6 files changed, 145 insertions(+), 38 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 48da3ceaf47..949e1376444 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -112,7 +112,7 @@ static void context_destroy_fbo(struct wined3d_context *context, GLuint *fbo) } /* GL locking is done by the caller */ -static void context_apply_attachment_filter_states(IWineD3DSurfaceImpl *surface) +static void context_apply_attachment_filter_states(IWineD3DSurfaceImpl *surface, DWORD location) { IWineD3DBaseTextureImpl *texture_impl; @@ -123,18 +123,35 @@ static void context_apply_attachment_filter_states(IWineD3DSurfaceImpl *surface) IWineD3DDeviceImpl *device = surface->resource.device; BOOL update_minfilter = FALSE; BOOL update_magfilter = FALSE; + struct gl_texture *gl_tex; - if (texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] != WINED3DTEXF_POINT - || texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] != WINED3DTEXF_NONE) + switch (location) { - texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; - texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE; + case SFLAG_INTEXTURE: + gl_tex = &texture_impl->baseTexture.texture_rgb; + break; + + case SFLAG_INSRGBTEX: + gl_tex = &texture_impl->baseTexture.texture_srgb; + break; + + default: + ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location); + IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl); + return; + } + + if (gl_tex->states[WINED3DTEXSTA_MINFILTER] != WINED3DTEXF_POINT + || gl_tex->states[WINED3DTEXSTA_MIPFILTER] != WINED3DTEXF_NONE) + { + gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; + gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE; update_minfilter = TRUE; } - if (texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] != WINED3DTEXF_POINT) + if (gl_tex->states[WINED3DTEXSTA_MAGFILTER] != WINED3DTEXF_POINT) { - texture_impl->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; + gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; update_magfilter = TRUE; } @@ -168,7 +185,7 @@ static void context_apply_attachment_filter_states(IWineD3DSurfaceImpl *surface) glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding); } - glBindTexture(bind_target, surface->texture_name); + glBindTexture(bind_target, gl_tex->name); if (update_minfilter) glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (update_magfilter) glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture(bind_target, old_binding); @@ -209,7 +226,7 @@ void context_attach_depth_stencil_fbo(struct wined3d_context *context, else { surface_prepare_texture(depth_stencil, gl_info, FALSE); - context_apply_attachment_filter_states(depth_stencil); + context_apply_attachment_filter_states(depth_stencil, SFLAG_INTEXTURE); if (format_flags & WINED3DFMT_FLAG_DEPTH) { @@ -252,7 +269,7 @@ void context_attach_depth_stencil_fbo(struct wined3d_context *context, /* GL locking is done by the caller */ static void context_attach_surface_fbo(const struct wined3d_context *context, - GLenum fbo_target, DWORD idx, IWineD3DSurfaceImpl *surface) + GLenum fbo_target, DWORD idx, IWineD3DSurfaceImpl *surface, DWORD location) { const struct wined3d_gl_info *gl_info = context->gl_info; @@ -260,11 +277,26 @@ static void context_attach_surface_fbo(const struct wined3d_context *context, if (surface) { - surface_prepare_texture(surface, gl_info, FALSE); - context_apply_attachment_filter_states(surface); + switch (location) + { + case SFLAG_INTEXTURE: + surface_prepare_texture(surface, gl_info, FALSE); + context_apply_attachment_filter_states(surface, location); + gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, + surface->texture_target, surface->texture_name, surface->texture_level); + break; - gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, surface->texture_target, - surface->texture_name, surface->texture_level); + case SFLAG_INSRGBTEX: + surface_prepare_texture(surface, gl_info, TRUE); + context_apply_attachment_filter_states(surface, location); + gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, + surface->texture_target, surface->texture_name_srgb, surface->texture_level); + break; + + default: + ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location); + break; + } checkGLcall("glFramebufferTexture2D()"); } else @@ -295,6 +327,9 @@ static void context_check_fbo_status(struct wined3d_context *context, GLenum tar return; } + FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location), + context->current_fbo->location); + /* Dump the FBO attachments */ for (i = 0; i < gl_info->limits.buffers; ++i) { @@ -317,7 +352,7 @@ static void context_check_fbo_status(struct wined3d_context *context, GLenum tar } static struct fbo_entry *context_create_fbo_entry(struct wined3d_context *context, - IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil) + IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location) { const struct wined3d_gl_info *gl_info = context->gl_info; struct fbo_entry *entry; @@ -326,6 +361,7 @@ static struct fbo_entry *context_create_fbo_entry(struct wined3d_context *contex entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets)); memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets)); entry->depth_stencil = depth_stencil; + entry->location = location; entry->attached = FALSE; entry->id = 0; @@ -335,7 +371,7 @@ static struct fbo_entry *context_create_fbo_entry(struct wined3d_context *contex /* GL locking is done by the caller */ static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target, IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, - struct fbo_entry *entry) + DWORD location, struct fbo_entry *entry) { const struct wined3d_gl_info *gl_info = context->gl_info; @@ -344,6 +380,7 @@ static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum targ memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets)); entry->depth_stencil = depth_stencil; + entry->location = location; entry->attached = FALSE; } @@ -364,7 +401,7 @@ static void context_destroy_fbo_entry(struct wined3d_context *context, struct fb /* GL locking is done by the caller */ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target, - IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil) + IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location) { const struct wined3d_gl_info *gl_info = context->gl_info; struct fbo_entry *entry; @@ -373,7 +410,7 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, { if (!memcmp(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets)) - && entry->depth_stencil == depth_stencil) + && entry->depth_stencil == depth_stencil && entry->location == location) { list_remove(&entry->entry); list_add_head(&context->fbo_list, &entry->entry); @@ -383,14 +420,14 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES) { - entry = context_create_fbo_entry(context, render_targets, depth_stencil); + entry = context_create_fbo_entry(context, render_targets, depth_stencil, location); list_add_head(&context->fbo_list, &entry->entry); ++context->fbo_entry_count; } else { entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry); - context_reuse_fbo_entry(context, target, render_targets, depth_stencil, entry); + context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry); list_remove(&entry->entry); list_add_head(&context->fbo_list, &entry->entry); } @@ -411,7 +448,7 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ /* Apply render targets */ for (i = 0; i < gl_info->limits.buffers; ++i) { - context_attach_surface_fbo(context, target, i, entry->render_targets[i]); + context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location); } /* Apply depth targets */ @@ -429,16 +466,16 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ for (i = 0; i < gl_info->limits.buffers; ++i) { if (entry->render_targets[i]) - context_apply_attachment_filter_states(entry->render_targets[i]); + context_apply_attachment_filter_states(entry->render_targets[i], entry->location); } if (entry->depth_stencil) - context_apply_attachment_filter_states(entry->depth_stencil); + context_apply_attachment_filter_states(entry->depth_stencil, SFLAG_INTEXTURE); } } /* GL locking is done by the caller */ static void context_apply_fbo_state(struct wined3d_context *context, GLenum target, - IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil) + IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location) { struct fbo_entry *entry, *entry2; @@ -455,7 +492,7 @@ static void context_apply_fbo_state(struct wined3d_context *context, GLenum targ if (render_targets) { - context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil); + context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location); context_apply_fbo_entry(context, target, context->current_fbo); } else @@ -469,18 +506,18 @@ static void context_apply_fbo_state(struct wined3d_context *context, GLenum targ /* GL locking is done by the caller */ void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target, - IWineD3DSurfaceImpl *render_target, IWineD3DSurfaceImpl *depth_stencil) + IWineD3DSurfaceImpl *render_target, IWineD3DSurfaceImpl *depth_stencil, DWORD location) { if (surface_is_offscreen(render_target)) { UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets); context->blit_targets[0] = render_target; if (clear_size) memset(&context->blit_targets[1], 0, clear_size); - context_apply_fbo_state(context, target, context->blit_targets, depth_stencil); + context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location); } else { - context_apply_fbo_state(context, target, NULL, NULL); + context_apply_fbo_state(context, target, NULL, NULL, location); } } @@ -2036,7 +2073,7 @@ void context_apply_blit_state(struct wined3d_context *context, IWineD3DDeviceImp surface_internal_preload(context->current_rt, SRGB_RGB); ENTER_GL(); - context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, context->current_rt, NULL); + context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, context->current_rt, NULL, SFLAG_INTEXTURE); LEAVE_GL(); } else @@ -2083,11 +2120,11 @@ void context_apply_clear_state(struct wined3d_context *context, IWineD3DDeviceIm context->blit_targets[i] = NULL; ++i; } - context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil); + context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE); } else { - context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL); + context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE); } LEAVE_GL(); @@ -2161,13 +2198,14 @@ void context_apply_draw_state(struct wined3d_context *context, IWineD3DDeviceImp if (!context->render_offscreen) { ENTER_GL(); - context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL); + context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE); LEAVE_GL(); } else { ENTER_GL(); - context_apply_fbo_state(context, GL_FRAMEBUFFER, device->render_targets, device->depth_stencil); + context_apply_fbo_state(context, GL_FRAMEBUFFER, device->render_targets, + device->depth_stencil, SFLAG_INTEXTURE); LEAVE_GL(); } } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index df9e1d66122..cd2ad97e26f 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5821,7 +5821,7 @@ void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surfa } else { TRACE("Source surface %p is offscreen\n", src_surface); ENTER_GL(); - context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL); + context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, SFLAG_INTEXTURE); glReadBuffer(GL_COLOR_ATTACHMENT0); checkGLcall("glReadBuffer()"); } @@ -5849,7 +5849,7 @@ void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surfa TRACE("Destination surface %p is offscreen\n", dst_surface); ENTER_GL(); - context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL); + context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, SFLAG_INTEXTURE); context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0); } diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 7abae54fccf..995d00c6d54 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -4206,6 +4206,43 @@ static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT context_release(context); } +static void surface_load_srgb_fbo(IWineD3DSurfaceImpl *surface, DWORD location) +{ + IWineD3DDeviceImpl *device = surface->resource.device; + const struct wined3d_gl_info *gl_info; + struct wined3d_context *context; + + context = context_acquire(device, NULL); + gl_info = context->gl_info; + + ENTER_GL(); + + context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, surface, NULL, + location == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX); + glReadBuffer(GL_COLOR_ATTACHMENT0); + checkGLcall("glReadBuffer()"); + + context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, surface, NULL, location); + context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3)); + + glDisable(GL_SCISSOR_TEST); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); + + gl_info->fbo_ops.glBlitFramebuffer(0, 0, surface->currentDesc.Width, surface->currentDesc.Height, + 0, 0, surface->currentDesc.Width, surface->currentDesc.Height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + checkGLcall("glBlitFramebuffer()"); + + LEAVE_GL(); + + context_release(context); +} + HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect) { IWineD3DDeviceImpl *device = surface->resource.device; @@ -4360,10 +4397,20 @@ HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RE } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ { + const DWORD attach_flags = WINED3DFMT_FLAG_FBO_ATTACHABLE | WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB; + if (drawable_read_ok && (surface->Flags & SFLAG_INDRAWABLE)) { read_from_framebuffer_texture(surface, flag == SFLAG_INSRGBTEX); } + else if (surface->Flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE) + && (surface->resource.format_desc->Flags & attach_flags) == attach_flags + && fbo_blit_supported(gl_info, BLIT_OP_BLIT, + NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc, + NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc)) + { + surface_load_srgb_fbo(surface, flag); + } else { /* Upload from system memory */ diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 87db680f9cf..6f99dc1c22f 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -120,7 +120,7 @@ static void swapchain_blit(IWineD3DSwapChainImpl *This, struct wined3d_context * if (gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format_desc->color_fixup)) { ENTER_GL(); - context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, backbuffer, NULL); + context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, backbuffer, NULL, SFLAG_INTEXTURE); glReadBuffer(GL_COLOR_ATTACHMENT0); context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL); diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 7a36998fdff..661139cfe87 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1056,6 +1056,26 @@ static void check_fbo_compat(const struct wined3d_gl_info *gl_info, struct wined } } + if (format_desc->glInternal != format_desc->glGammaInternal) + { + glTexImage2D(GL_TEXTURE_2D, 0, format_desc->glGammaInternal, 16, 16, 0, + format_desc->glFormat, format_desc->glType, NULL); + gl_info->fbo_ops.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + + status = gl_info->fbo_ops.glCheckFramebufferStatus(GL_FRAMEBUFFER); + checkGLcall("Framebuffer format check"); + + if (status == GL_FRAMEBUFFER_COMPLETE) + { + TRACE("Format %s's sRGB format is FBO attachable.\n", debug_d3dformat(format_desc->format)); + format_desc->Flags |= WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB; + } + else + { + WARN("Format %s's sRGB format is not FBO attachable.\n", debug_d3dformat(format_desc->format)); + } + } + glDeleteTextures(1, &tex); LEAVE_GL(); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d366945a061..fe44eae7f27 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1164,7 +1164,7 @@ void context_apply_clear_state(struct wined3d_context *context, IWineD3DDeviceIm UINT rt_count, IWineD3DSurfaceImpl **rts, IWineD3DSurfaceImpl *depth_stencil) DECLSPEC_HIDDEN; void context_apply_draw_state(struct wined3d_context *context, IWineD3DDeviceImpl *device) DECLSPEC_HIDDEN; void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target, - IWineD3DSurfaceImpl *render_target, IWineD3DSurfaceImpl *depth_stencil) DECLSPEC_HIDDEN; + IWineD3DSurfaceImpl *render_target, IWineD3DSurfaceImpl *depth_stencil, DWORD location) DECLSPEC_HIDDEN; void context_attach_depth_stencil_fbo(struct wined3d_context *context, GLenum fbo_target, IWineD3DSurfaceImpl *depth_stencil, BOOL use_render_buffer) DECLSPEC_HIDDEN; void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint *fbo) DECLSPEC_HIDDEN; @@ -1979,6 +1979,7 @@ struct fbo_entry struct list entry; IWineD3DSurfaceImpl **render_targets; IWineD3DSurfaceImpl *depth_stencil; + DWORD location; BOOL attached; GLuint id; }; @@ -2929,7 +2930,7 @@ extern WINED3DFORMAT pixelformat_for_depth(DWORD depth) DECLSPEC_HIDDEN; #define WINED3DFMT_FLAG_RENDERTARGET 0x00000010 #define WINED3DFMT_FLAG_FOURCC 0x00000020 #define WINED3DFMT_FLAG_FBO_ATTACHABLE 0x00000040 -#define WINED3DFMT_FLAG_COMPRESSED 0x00000080 +#define WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB 0x00000080 #define WINED3DFMT_FLAG_GETDC 0x00000100 #define WINED3DFMT_FLAG_FLOAT 0x00000200 #define WINED3DFMT_FLAG_BUMPMAP 0x00000400 @@ -2937,6 +2938,7 @@ extern WINED3DFORMAT pixelformat_for_depth(DWORD depth) DECLSPEC_HIDDEN; #define WINED3DFMT_FLAG_SRGB_WRITE 0x00001000 #define WINED3DFMT_FLAG_VTF 0x00002000 #define WINED3DFMT_FLAG_SHADOW 0x00004000 +#define WINED3DFMT_FLAG_COMPRESSED 0x00008000 struct wined3d_format_desc {