/* Real-time YUYV-DXT5 compression. Copyright (c) Outerra Written by: Brano Kemen Derived from Real-time DXT1 & YCoCg DXT5 compression code by NVIDIA, copyright below. */ /* Real-time DXT1 & YCoCg DXT5 compression (Cg 2.0) Copyright (c) NVIDIA Corporation. Written by: Ignacio Castano Thanks to JMP van Waveren, Simon Green, Eric Werness, Simon Brown Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //VERTEX_SHADER void v_compress( int2 pos, out float4 opos : POSITION, ) { opos = float4(pos*2-1,-1,1); } ///Get intensity (Y) data for 4x8 pixel block void ExtractColorBlockYY( out float2 col[16], sampler2D image, int2 coord) { for (int i=0; i<4; i++) { for (int j=0; j<4; j++) { float3 color = texelFetch(image, coord + int2(j,i), 0); col[i*4+j].x = dot(float3(0.2215, 0.7154, 0.0721), pow(color, float3(1.0/2.2))); } } for (int i=0; i<4; i++) { for (int j=4; j<8; j++) { float3 color = texelFetch(image, coord + int2(j,i), 0); col[i*4+j-4].y = dot(float3(0.2215, 0.7154, 0.0721), pow(color, float3(1.0/2.2))); } } } const float offset = 128.0 / 255.0; ///Get chrominance (UV) data for 4x8 pixel block, 2 pixels average void ExtractColorBlockUV( out float2 col[16], sampler2DMS image, int2 coord) { for (int i=0; i<4; i++) { for (int j=0; j<8; j+=2) { float3 color0 = texelFetch(image, coord + int2(j,i), 0); float3 color1 = texelFetch(image, coord + int2(j+1,i), 0); float3 color = 0.5 * (color0 + color1); col[i*4+(j>>1)].x = dot(float3(-0.1145, -0.3855, 0.5000), pow(color, float3(1.0/2.2))) + offset; col[i*4+(j>>1)].y = dot(float3(0.5016, -0.4556, -0.0459), pow(color, float3(1.0/2.2))) + offset; } } } // find minimum and maximum colors based on bounding box in color space void FindMinMaxBox(float2 block[16], out float2 mincol, out float2 maxcol) { mincol = block[0]; maxcol = block[0]; for (int i = 1; i < 16; i++) { mincol = min(mincol, block[i]); maxcol = max(maxcol, block[i]); } } void InsetYBBox(inout float2 mincol, inout float2 maxcol) { float2 inset = (maxcol - mincol) / 32.0 - (16.0 / 255.0) / 32.0; mincol = saturate(mincol + inset); maxcol = saturate(maxcol - inset); } uint2 EmitValueEndPoints(float2 mincol, float2 maxcol) { //InsetYBBox(mincol, maxcol); uint2 c0 = uint2(round(mincol * 255)); uint2 c1 = uint2(round(maxcol * 255)); return (c0 << 8U) | c1; } // Optimized index selection uint4 EmitValueIndices(float2 block[16], float2 minv, float2 maxv) { const int ALPHA_RANGE = 7; float2 bias = maxv + (maxv - minv) / (2.0 * ALPHA_RANGE); float2 scale = 1.0f / (maxv - minv); uint4 indices = uint4(0U); for (int i = 0; i < 6; i++) { uint2 index = uint2(saturate((bias - block[i]) * scale) * ALPHA_RANGE); indices.xz |= index << uint(3 * i); } for (int i = 6; i < 16; i++) { uint2 index = uint2(saturate((bias - block[i]) * scale) * ALPHA_RANGE); indices.yw |= index << uint(3 * i - 18); } uint4 i0 = (indices >> 0U) & 0x09249249U; uint4 i1 = (indices >> 1U) & 0x09249249U; uint4 i2 = (indices >> 2U) & 0x09249249U; i2 ^= i0 & i1; i1 ^= i0; i0 ^= (i1 | i2); indices.xz = (i2.xz << 2U) | (i1.xz << 1U) | i0.xz; indices.yw = (((i2.yw << 2U) | (i1.yw << 1U) | i0.yw) << 2U) | (indices.xz >> 16U); indices.xz <<= 16U; return indices; } uint4 encodeDXT( float2 block[16] ) { // find min and max colors float2 mincol, maxcol; FindMinMaxBox(block, mincol, maxcol); InsetYBBox(mincol, maxcol); uint4 OUT; OUT.xz = EmitValueEndPoints(mincol, maxcol); uint4 indices = EmitValueIndices(block, mincol, maxcol); OUT.xz |= indices.xz; OUT.yw = indices.yw; return OUT; } // compress a 4x4 block to YUYV-DXT5 format // integer version, renders to 4 x int32 buffer //FRAGMENT_SHADER uint4 f_compress_yuyv( float4 fragcoord : FRAGCOORD, uniform sampler2D image ) { int2 co = int2(4 * fragcoord.xy); int2 cb = co & int2(~7,~3); bool Y = co.x - cb.x < 4; float2 block[16]; if(Y) ExtractColorBlockYY(block, image, cb); else ExtractColorBlockUV(block, image, cb); return encodeDXT(block); }