From: Connor McAdams conmanx360@gmail.com
Signed-off-by: Connor McAdams conmanx360@gmail.com Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- This supersedes patch 149253.
v2: Fix the maths in the comments, as pointed out by Józef. --- dlls/wined3d/resource.c | 9 ++ dlls/wined3d/texture.c | 40 ++++-- dlls/wined3d/utils.c | 286 +++++++++++++++++++++++++++++++++++++---- dlls/wined3d/wined3d_private.h | 6 + 4 files changed, 304 insertions(+), 37 deletions(-)
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c index b5dcdf012db..bf54245276a 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c @@ -477,3 +477,12 @@ void wined3d_resource_update_draw_binding(struct wined3d_resource *resource) resource->draw_binding = WINED3D_LOCATION_TEXTURE_RGB; } } + +const struct wined3d_format *wined3d_resource_get_decompress_format(struct wined3d_resource *resource, + const struct wined3d_context *context) +{ + if (resource->format_flags & (WINED3DFMT_FLAG_SRGB_READ | WINED3DFMT_FLAG_SRGB_WRITE) + && !(context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)) + return wined3d_get_format(context->gl_info, WINED3DFMT_B8G8R8A8_UNORM_SRGB, resource->usage); + return wined3d_get_format(context->gl_info, WINED3DFMT_B8G8R8A8_UNORM, resource->usage); +} diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index c316906a957..ebdacfa2ee0 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -1727,7 +1727,13 @@ void wined3d_texture_prepare_texture(struct wined3d_texture *texture, struct win if (texture->flags & alloc_flag) return;
- if (format->conv_byte_count) + if (texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS) + { + TRACE("WINED3DFMT_FLAG_DECOMPRESS set.\n"); + texture->flags |= WINED3D_TEXTURE_CONVERTED; + format = wined3d_resource_get_decompress_format(&texture->resource, context); + } + else if (format->conv_byte_count) { texture->flags |= WINED3D_TEXTURE_CONVERTED; } @@ -1897,6 +1903,7 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s void *converted_mem = NULL; struct wined3d_format f; unsigned int level; + BOOL decompress; GLenum target;
TRACE("texture %p, sub_resource_idx %u, context %p, format %s, src_box %s, data {%#x:%p}, " @@ -1948,20 +1955,31 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s bo.addr += src_box->left * format->byte_count; }
- if (format->upload) + decompress = texture->resource.format_flags & WINED3DFMT_FLAG_DECOMPRESS; + if (format->upload || decompress) { + const struct wined3d_format *compressed_format = format; unsigned int dst_row_pitch, dst_slice_pitch; void *src_mem;
- if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS) - ERR("Converting a block-based format.\n"); + if (decompress) + { + format = wined3d_resource_get_decompress_format(&texture->resource, context); + } + else + { + if (texture->resource.format_flags & WINED3DFMT_FLAG_BLOCKS) + ERR("Converting a block-based format.\n");
- f = *format; - f.byte_count = format->conv_byte_count; - format = &f; + f = *format; + f.byte_count = format->conv_byte_count; + format = &f; + }
wined3d_format_calculate_pitch(format, 1, update_w, update_h, &dst_row_pitch, &dst_slice_pitch);
+ /* Note that uploading 3D textures may require quite some address + * space; it may make sense to upload them per-slice instead. */ if (!(converted_mem = heap_calloc(update_d, dst_slice_pitch))) { ERR("Failed to allocate upload buffer.\n"); @@ -1970,8 +1988,12 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s
src_mem = context_map_bo_address(context, &bo, src_slice_pitch, GL_PIXEL_UNPACK_BUFFER, WINED3D_MAP_READ); - format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch, - dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d); + if (decompress) + compressed_format->decompress(src_mem, converted_mem, src_row_pitch, src_slice_pitch, + dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d); + else + format->upload(src_mem, converted_mem, src_row_pitch, src_slice_pitch, + dst_row_pitch, dst_slice_pitch, update_w, update_h, update_d); context_unmap_bo_address(context, &bo, GL_PIXEL_UNPACK_BUFFER);
bo.buffer_object = 0; diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 937c1bc0df6..283e73015cb 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -339,6 +339,230 @@ static const struct wined3d_format_base_flags format_base_flags[] = {WINED3DFMT_RESZ, WINED3DFMT_FLAG_EXTENSION}, };
+static void rgb888_from_rgb565(WORD rgb565, BYTE *r, BYTE *g, BYTE *b) +{ + BYTE c; + + /* (2⁸ - 1) / (2⁵ - 1) ≈ 2⁸ / 2⁵ + 2⁸ / 2¹⁰ + * (2⁸ - 1) / (2⁶ - 1) ≈ 2⁸ / 2⁶ + 2⁸ / 2¹² */ + c = rgb565 >> 11; + *r = (c << 3) + (c >> 2); + c = (rgb565 >> 5) & 0x3f; + *g = (c << 2) + (c >> 4); + c = rgb565 & 0x1f; + *b = (c << 3) + (c >> 2); +} + +static void build_dxtn_colour_table(WORD colour0, WORD colour1, + DWORD colour_table[4], enum wined3d_format_id format_id) +{ + unsigned int i; + struct + { + BYTE r, g, b; + } c[4]; + + rgb888_from_rgb565(colour0, &c[0].r, &c[0].g, &c[0].b); + rgb888_from_rgb565(colour1, &c[1].r, &c[1].g, &c[1].b); + + if (format_id == WINED3DFMT_BC1_UNORM && colour0 <= colour1) + { + c[2].r = (c[0].r + c[1].r) / 2; + c[2].g = (c[0].g + c[1].g) / 2; + c[2].b = (c[0].b + c[1].b) / 2; + + c[3].r = 0; + c[3].g = 0; + c[3].b = 0; + } + else + { + for (i = 0; i < 2; ++i) + { + c[i + 2].r = (2 * c[i].r + c[1 - i].r) / 3; + c[i + 2].g = (2 * c[i].g + c[1 - i].g) / 3; + c[i + 2].b = (2 * c[i].b + c[1 - i].b) / 3; + } + } + + for (i = 0; i < 4; ++i) + { + colour_table[i] = (c[i].r << 16) | (c[i].g << 8) | c[i].b; + } +} + +static void build_dxtn_alpha_table(BYTE alpha0, BYTE alpha1, BYTE alpha_table[8]) +{ + unsigned int i; + + alpha_table[0] = alpha0; + alpha_table[1] = alpha1; + + if (alpha0 > alpha1) + { + for (i = 0; i < 6; ++i) + { + alpha_table[2 + i] = ((6 - i) * alpha0 + (i + 1) * alpha1) / 7; + } + return; + } + else + { + for (i = 0; i < 4; ++i) + { + alpha_table[2 + i] = ((4 - i) * alpha0 + (i + 1) * alpha1) / 5; + } + alpha_table[6] = 0x00; + alpha_table[7] = 0xff; + } +} + +static void decompress_dxtn_block(const BYTE *src, BYTE *dst, unsigned int width, + unsigned int height, unsigned int dst_row_pitch, enum wined3d_format_id format_id) +{ + const UINT64 *s = (const UINT64 *)src; + BOOL bc1_alpha = FALSE; + DWORD colour_table[4]; + BYTE alpha_table[8]; + UINT64 alpha_bits; + DWORD colour_bits; + unsigned int x, y; + BYTE colour_idx; + DWORD *dst_row; + BYTE alpha; + + if (format_id == WINED3DFMT_BC1_UNORM) + { + WORD colour0, colour1; + + alpha_bits = 0; + + colour0 = s[0] & 0xffff; + colour1 = (s[0] >> 16) & 0xffff; + colour_bits = (s[0] >> 32) & 0xffffffff; + build_dxtn_colour_table(colour0, colour1, colour_table, format_id); + if (colour0 <= colour1) + bc1_alpha = TRUE; + } + else + { + alpha_bits = s[0]; + if (format_id == WINED3DFMT_BC3_UNORM) + { + build_dxtn_alpha_table(alpha_bits & 0xff, (alpha_bits >> 8) & 0xff, alpha_table); + alpha_bits >>= 16; + } + + colour_bits = (s[1] >> 32) & 0xffffffff; + build_dxtn_colour_table(s[1] & 0xffff, (s[1] >> 16) & 0xffff, colour_table, format_id); + } + + for (y = 0; y < height; ++y) + { + dst_row = (DWORD *)&dst[y * dst_row_pitch]; + for (x = 0; x < width; ++x) + { + colour_idx = (colour_bits >> (y * 8 + x * 2)) & 0x3; + switch (format_id) + { + case WINED3DFMT_BC1_UNORM: + alpha = bc1_alpha && colour_idx == 3 ? 0x00 : 0xff; + break; + + case WINED3DFMT_BC2_UNORM: + alpha = (alpha_bits >> (y * 16 + x * 4)) & 0xf; + /* (2⁸ - 1) / (2⁴ - 1) ≈ 2⁸ / 2⁴ + 2⁸ / 2⁸ */ + alpha |= alpha << 4; + break; + + case WINED3DFMT_BC3_UNORM: + alpha = alpha_table[(alpha_bits >> (y * 12 + x * 3)) & 0x7]; + break; + + default: + alpha = 0xff; + break; + } + dst_row[x] = (alpha << 24) | colour_table[colour_idx]; + } + } +} + +static void decompress_dxtn(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, + unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth, enum wined3d_format_id format_id) +{ + unsigned int block_byte_count, block_w, block_h; + const BYTE *src_row, *src_slice = src; + BYTE *dst_row, *dst_slice = dst; + unsigned int x, y, z; + + block_byte_count = format_id == WINED3DFMT_BC1_UNORM ? 8 : 16; + + for (z = 0; z < depth; ++z) + { + src_row = src_slice; + dst_row = dst_slice; + for (y = 0; y < height; y += 4) + { + for (x = 0; x < width; x += 4) + { + block_w = min(width - x, 4); + block_h = min(height - y, 4); + decompress_dxtn_block(&src_row[x * (block_byte_count / 4)], + &dst_row[x * 4], block_w, block_h, dst_row_pitch, format_id); + } + src_row += src_row_pitch; + dst_row += dst_row_pitch * 4; + } + src_slice += src_slice_pitch; + dst_slice += dst_slice_pitch; + } +} + +static void decompress_bc3(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, + unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth) +{ + decompress_dxtn(src, dst, src_row_pitch, src_slice_pitch, dst_row_pitch, + dst_slice_pitch, width, height, depth, WINED3DFMT_BC3_UNORM); +} + +static void decompress_bc2(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, + unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth) +{ + decompress_dxtn(src, dst, src_row_pitch, src_slice_pitch, dst_row_pitch, + dst_slice_pitch, width, height, depth, WINED3DFMT_BC2_UNORM); +} + +static void decompress_bc1(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, + unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth) +{ + decompress_dxtn(src, dst, src_row_pitch, src_slice_pitch, dst_row_pitch, + dst_slice_pitch, width, height, depth, WINED3DFMT_BC1_UNORM); +} + +static const struct wined3d_format_decompress_info +{ + enum wined3d_format_id id; + void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth); +} +format_decompress_info[] = +{ + {WINED3DFMT_DXT1, decompress_bc1}, + {WINED3DFMT_DXT2, decompress_bc2}, + {WINED3DFMT_DXT3, decompress_bc2}, + {WINED3DFMT_DXT4, decompress_bc3}, + {WINED3DFMT_DXT5, decompress_bc3}, + {WINED3DFMT_BC1_UNORM, decompress_bc1}, + {WINED3DFMT_BC2_UNORM, decompress_bc2}, + {WINED3DFMT_BC3_UNORM, decompress_bc3}, +}; + struct wined3d_format_block_info { enum wined3d_format_id id; @@ -437,6 +661,9 @@ struct wined3d_format_texture_info void (*download)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned int dst_slice_pitch, unsigned int width, unsigned int height, unsigned int depth); + void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch, + unsigned int dst_row_pitch, unsigned int dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth); };
static void convert_l4a4_unorm(const BYTE *src, BYTE *dst, UINT src_row_pitch, UINT src_slice_pitch, @@ -1897,6 +2124,34 @@ static BOOL init_format_block_info(struct wined3d_gl_info *gl_info) return TRUE; }
+/* Most compressed formats are not supported for 3D textures by OpenGL. + * + * In the case of the S3TC/DXTn formats, NV_texture_compression_vtc provides + * these formats for 3D textures, but unfortunately the block layout is + * different from the one used by Direct3D. + * + * Since applications either don't check format availability at all before + * using these, or refuse to run without them, we decompress them on upload. + * + * Affected applications include "Heroes VI", "From Dust", "Halo Online" and + * "Eldorado". */ +static BOOL init_format_decompress_info(struct wined3d_gl_info *gl_info) +{ + struct wined3d_format *format; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format_decompress_info); ++i) + { + if (!(format = get_format_internal(gl_info, format_decompress_info[i].id))) + return FALSE; + + format->flags[WINED3D_GL_RES_TYPE_TEX_3D] |= WINED3DFMT_FLAG_DECOMPRESS; + format->decompress = format_decompress_info[i].decompress; + } + + return TRUE; +} + static GLenum wined3d_gl_type_to_enum(enum wined3d_gl_resource_type type) { switch (type) @@ -3390,34 +3645,8 @@ static void apply_format_fixups(struct wined3d_adapter *adapter, struct wined3d_ } }
- /* GL_EXT_texture_compression_s3tc does not support 3D textures. Some Windows drivers - * for dx9 GPUs support it, some do not, so not supporting DXTn volumes is OK for d3d9. - * - * Note that GL_NV_texture_compression_vtc adds this functionality to OpenGL, but the - * block layout is not compatible with the one used by d3d. See volume_dxt5_test. */ - idx = get_format_idx(WINED3DFMT_DXT1); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_DXT2); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_DXT3); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_DXT4); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_DXT5); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC1_UNORM); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC1_UNORM_SRGB); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC2_UNORM); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC2_UNORM_SRGB); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC3_UNORM); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - idx = get_format_idx(WINED3DFMT_BC3_UNORM_SRGB); - gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; - /* Similarly with ATI1N / ATI2N and GL_ARB_texture_compression_rgtc. */ + /* These formats are not supported for 3D textures. See also + * WINED3DFMT_FLAG_DECOMPRESS. */ idx = get_format_idx(WINED3DFMT_ATI1N); gl_info->formats[idx].flags[WINED3D_GL_RES_TYPE_TEX_3D] &= ~WINED3DFMT_FLAG_TEXTURE; idx = get_format_idx(WINED3DFMT_ATI2N); @@ -3742,6 +3971,7 @@ BOOL wined3d_adapter_init_format_info(struct wined3d_adapter *adapter, struct wi
if (!init_format_base_info(gl_info)) return FALSE; if (!init_format_block_info(gl_info)) goto fail; + if (!init_format_decompress_info(gl_info)) goto fail;
if (!ctx) /* WINED3D_NO3D */ return TRUE; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index ece41ebd06c..25f7cb2416e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3081,6 +3081,8 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device * void resource_unload(struct wined3d_resource *resource) DECLSPEC_HIDDEN; BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN; void wined3d_resource_free_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN; +const struct wined3d_format *wined3d_resource_get_decompress_format(struct wined3d_resource *resource, + const struct wined3d_context *context) DECLSPEC_HIDDEN; GLbitfield wined3d_resource_gl_map_flags(DWORD d3d_flags) DECLSPEC_HIDDEN; GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags) DECLSPEC_HIDDEN; BOOL wined3d_resource_is_offscreen(struct wined3d_resource *resource) DECLSPEC_HIDDEN; @@ -4231,6 +4233,7 @@ extern enum wined3d_format_id pixelformat_for_depth(DWORD depth) DECLSPEC_HIDDEN #define WINED3DFMT_FLAG_EXTENSION 0x00000020 #define WINED3DFMT_FLAG_FBO_ATTACHABLE 0x00000040 #define WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB 0x00000080 +#define WINED3DFMT_FLAG_DECOMPRESS 0x00000100 #define WINED3DFMT_FLAG_FLOAT 0x00000200 #define WINED3DFMT_FLAG_BUMPMAP 0x00000400 #define WINED3DFMT_FLAG_SRGB_READ 0x00000800 @@ -4304,6 +4307,9 @@ struct wined3d_format void (*download)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch, unsigned int dst_row_pitch, unsigned dst_slice_pitch, unsigned int width, unsigned int height, unsigned int depth); + void (*decompress)(const BYTE *src, BYTE *dst, unsigned int src_row_pitch, unsigned int src_slice_pitch, + unsigned int dst_row_pitch, unsigned dst_slice_pitch, + unsigned int width, unsigned int height, unsigned int depth);
enum wined3d_format_id typeless_id; GLenum gl_view_class;
On Mon, Aug 6, 2018 at 11:05 PM Henri Verbeet hverbeet@codeweavers.com wrote:
From: Connor McAdams conmanx360@gmail.com
/* Note that uploading 3D textures may require quite some address
* space; it may make sense to upload them per-slice instead. */
I think Connor wrote (but probably didn't send) a version of this patch doing exactly that. Actually IIRC that was necessary to avoid running out of address space in Halo Online. Connor, do you want to prepare a followup patch to improve on that?
Tiny nitpick:
+static void build_dxtn_alpha_table(BYTE alpha0, BYTE alpha1, BYTE alpha_table[8]) +{
- unsigned int i;
- alpha_table[0] = alpha0;
- alpha_table[1] = alpha1;
- if (alpha0 > alpha1)
- {
for (i = 0; i < 6; ++i)
{
alpha_table[2 + i] = ((6 - i) * alpha0 + (i + 1) * alpha1) / 7;
}
return;
- }
- else
- {
for (i = 0; i < 4; ++i)
{
alpha_table[2 + i] = ((4 - i) * alpha0 + (i + 1) * alpha1) / 5;
}
alpha_table[6] = 0x00;
alpha_table[7] = 0xff;
- }
+}
Technically this is DXT5 / BC3 only, the function name could reflect that.
Yeah, I can. I think the conclusion that was came to in IRC at some point though was that it would turn out to be pretty ugly... Might need some back and forth on the specifics of doing it.
On Sun, Aug 12, 2018 at 5:55 PM, Matteo Bruni matteo.mystral@gmail.com wrote:
On Mon, Aug 6, 2018 at 11:05 PM Henri Verbeet hverbeet@codeweavers.com wrote:
From: Connor McAdams conmanx360@gmail.com
/* Note that uploading 3D textures may require quite some address
* space; it may make sense to upload them per-slice instead. */
I think Connor wrote (but probably didn't send) a version of this patch doing exactly that. Actually IIRC that was necessary to avoid running out of address space in Halo Online. Connor, do you want to prepare a followup patch to improve on that?
Tiny nitpick:
+static void build_dxtn_alpha_table(BYTE alpha0, BYTE alpha1, BYTE alpha_table[8]) +{
- unsigned int i;
- alpha_table[0] = alpha0;
- alpha_table[1] = alpha1;
- if (alpha0 > alpha1)
- {
for (i = 0; i < 6; ++i)
{
alpha_table[2 + i] = ((6 - i) * alpha0 + (i + 1) * alpha1) / 7;
}
return;
- }
- else
- {
for (i = 0; i < 4; ++i)
{
alpha_table[2 + i] = ((4 - i) * alpha0 + (i + 1) * alpha1) / 5;
}
alpha_table[6] = 0x00;
alpha_table[7] = 0xff;
- }
+}
Technically this is DXT5 / BC3 only, the function name could reflect that.