From 28409aed1a0cbf8d2e8d9d157d08c3f6d9a3f51a Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 16 Sep 2017 15:19:13 +0200 Subject: [PATCH] Add the GPU decoder itself. --- decoder.shader | 327 ++++++++++++++++++++++++++++++++++++++++++++++++ narabu.cpp | 328 +++++++++++++++++++++++++++++++++++++++++++++++++ util.cpp | 75 +++++++++++ util.h | 15 +++ 4 files changed, 745 insertions(+) create mode 100644 decoder.shader create mode 100644 narabu.cpp create mode 100644 util.cpp create mode 100644 util.h diff --git a/decoder.shader b/decoder.shader new file mode 100644 index 0000000..6d54e4d --- /dev/null +++ b/decoder.shader @@ -0,0 +1,327 @@ +#version 430 +#extension GL_ARB_shader_clock : enable + +#define ENABLE_TIMING 0 + +layout(local_size_x = 8, local_size_y = 8) in; +layout(r8ui) uniform restrict readonly uimage2D cum2sym_tex; +layout(rg16ui) uniform restrict readonly uimage2D dsyms_tex; +layout(r8) uniform restrict writeonly image2D out_tex; + +const uint prob_bits = 12; +const uint prob_scale = 1 << prob_bits; +const uint NUM_SYMS = 256; +const uint ESCAPE_LIMIT = NUM_SYMS - 1; + +// These need to be folded into quant_matrix. +const float dc_scalefac = 8.0; +const float quant_scalefac = 4.0; + +const float quant_matrix[64] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; +const uint ff_zigzag_direct[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +layout(std430, binding = 9) buffer layoutName +{ + uint data_SSBO[]; +}; +layout(std430, binding = 10) buffer layoutName2 +{ + uvec2 timing[10 * 64]; +}; + +struct CoeffStream { + uint src_offset, src_len, sign_offset, sign_len, extra_bits; +}; +layout(std430, binding = 0) buffer whatever3 +{ + CoeffStream streams[]; +}; + +uniform uint src_offset, src_len, sign_offset, sign_len, extra_bits; + +const uint RANS_BYTE_L = (1u << 23); // lower bound of our normalization interval + +uint last_offset = -1, ransbuf; + +uint get_rans_byte(uint offset) +{ + if (last_offset != (offset >> 2)) { + last_offset = offset >> 2; + ransbuf = data_SSBO[offset >> 2]; + } + return bitfieldExtract(ransbuf, 8 * int(offset & 3u), 8); + + // We assume little endian. +// return bitfieldExtract(data_SSBO[offset >> 2], 8 * int(offset & 3u), 8); +} + +void RansDecInit(out uint r, inout uint offset) +{ + uint x; + + x = get_rans_byte(offset); + x |= get_rans_byte(offset + 1) << 8; + x |= get_rans_byte(offset + 2) << 16; + x |= get_rans_byte(offset + 3) << 24; + offset += 4; + + r = x; +} + +uint RansDecGet(uint r, uint scale_bits) +{ + return r & ((1u << scale_bits) - 1); +} + +void RansDecAdvance(inout uint rans, inout uint offset, const uint start, const uint freq, uint prob_bits) +{ + const uint mask = (1u << prob_bits) - 1; + rans = freq * (rans >> prob_bits) + (rans & mask) - start; + + // renormalize + while (rans < RANS_BYTE_L) { + rans = (rans << 8) | get_rans_byte(offset++); + } +} + +uint cum2sym(uint bits, uint table) +{ + return imageLoad(cum2sym_tex, ivec2(bits, table)).x; +} + +uvec2 get_dsym(uint k, uint table) +{ + return imageLoad(dsyms_tex, ivec2(k, table)).xy; +} + +void idct_1d(inout float y0, inout float y1, inout float y2, inout float y3, inout float y4, inout float y5, inout float y6, inout float y7) +{ + const float a1 = 0.7071067811865474; // sqrt(2) + const float a2 = 0.5411961001461971; // cos(3/8 pi) * sqrt(2) + const float a4 = 1.3065629648763766; // cos(pi/8) * sqrt(2) + // static const float a5 = 0.5 * (a4 - a2); + const float a5 = 0.3826834323650897; + + // phase 2 (phase 1 is just moving around) + const float p2_4 = y5 - y3; + const float p2_5 = y1 + y7; + const float p2_6 = y1 - y7; + const float p2_7 = y5 + y3; + + // phase 3 + const float p3_2 = y2 - y6; + const float p3_3 = y2 + y6; + const float p3_5 = p2_5 - p2_7; + const float p3_7 = p2_5 + p2_7; + + // phase 4 + const float p4_2 = a1 * p3_2; + const float p4_4 = p2_4 * a2 + (p2_4 + p2_6) * a5; // Inverted. + const float p4_5 = a1 * p3_5; + const float p4_6 = p2_6 * a4 - (p2_4 + p2_6) * a5; + + // phase 5 + const float p5_0 = y0 + y4; + const float p5_1 = y0 - y4; + const float p5_3 = p4_2 + p3_3; + + // phase 6 + const float p6_0 = p5_0 + p5_3; + const float p6_1 = p5_1 + p4_2; + const float p6_2 = p5_1 - p4_2; + const float p6_3 = p5_0 - p5_3; + const float p6_5 = p4_5 + p4_4; + const float p6_6 = p4_5 + p4_6; + const float p6_7 = p4_6 + p3_7; + + // phase 7 + y0 = p6_0 + p6_7; + y1 = p6_1 + p6_6; + y2 = p6_2 + p6_5; + y3 = p6_3 - p4_4; + y4 = p6_3 + p4_4; + y5 = p6_2 - p6_5; + y6 = p6_1 - p6_6; + y7 = p6_0 - p6_7; +} + +shared float temp[64 * 8]; + +void pick_timer(inout uvec2 start, inout uvec2 t) +{ +#if ENABLE_TIMING + uvec2 now = clock2x32ARB(); + + uvec2 delta = now - start; + if (now.x < start.x) { + --delta.y; + } + + uvec2 new_t = t + delta; + if (new_t.x < t.x) { + ++new_t.y; + } + t = new_t; + + start = clock2x32ARB(); +#endif +} + +void main() +{ + uvec2 local_timing[10]; +#if ENABLE_TIMING + for (int timer_idx = 0; timer_idx < 10; ++timer_idx) { + local_timing[timer_idx] = uvec2(0, 0); + } + uvec2 start = clock2x32ARB(); +#else + uvec2 start; +#endif + + const uint num_blocks = 720 / 16; // FIXME: make a uniform + const uint thread_num = gl_LocalInvocationID.y * 8 + gl_LocalInvocationID.x; + + const uint block_row = gl_WorkGroupID.y; + //const uint coeff_num = ff_zigzag_direct[thread_num]; + const uint coeff_num = thread_num; + const uint stream_num = coeff_num * num_blocks + block_row; + //const uint stream_num = block_row * num_blocks + coeff_num; // HACK + const uint model_num = min((coeff_num % 8) + (coeff_num / 8), 7); + + // Initialize rANS decoder. + uint offset = streams[stream_num].src_offset; + uint rans; + RansDecInit(rans, offset); + + // Initialize sign bit decoder. TODO: this ought to be 32-bit-aligned instead! + uint soffset = streams[stream_num].sign_offset; + uint sign_buf = get_rans_byte(soffset++) >> streams[stream_num].extra_bits; + uint sign_bits_left = 8 - streams[stream_num].extra_bits; + + float q = (coeff_num == 0) ? 1.0 : (quant_matrix[coeff_num] * quant_scalefac / 128.0 / sqrt(2.0)); // FIXME: fold + q *= (1.0 / 255.0); + //int w = (coeff_num == 0) ? 32 : int(quant_matrix[coeff_num]); + int last_k = 0; + + pick_timer(start, local_timing[0]); + + for (uint block_idx = 40; block_idx --> 0; ) { + uint block_x = block_idx % 20; + uint block_y = block_idx / 20; + if (block_x == 19) last_k = 0; + + pick_timer(start, local_timing[1]); + + // rANS decode one coefficient across eight blocks (so 64x8 coefficients). + for (uint subblock_idx = 8; subblock_idx --> 0; ) { + // Read a symbol. + int k = int(cum2sym(RansDecGet(rans, prob_bits), model_num)); + uvec2 sym = get_dsym(k, model_num); + RansDecAdvance(rans, offset, sym.x, sym.y, prob_bits); + + if (k == ESCAPE_LIMIT) { + k = int(RansDecGet(rans, prob_bits)); + RansDecAdvance(rans, offset, k, 1, prob_bits); + } + if (k != 0) { + if (sign_bits_left == 0) { + sign_buf = get_rans_byte(soffset++); + sign_bits_left = 8; + } + if ((sign_buf & 1u) == 1u) k = -k; + --sign_bits_left; + sign_buf >>= 1; + } + + if (coeff_num == 0) { + k += last_k; + last_k = k; + } + + temp[subblock_idx * 64 + coeff_num] = k * q; + //temp[subblock_idx * 64 + 8 * y + x] = (2 * k * w * 4) / 32; // 100% matching unquant + } + + pick_timer(start, local_timing[2]); + + memoryBarrierShared(); + barrier(); + + pick_timer(start, local_timing[3]); + + // Horizontal DCT one row (so 64 rows). + idct_1d(temp[thread_num * 8 + 0], + temp[thread_num * 8 + 1], + temp[thread_num * 8 + 2], + temp[thread_num * 8 + 3], + temp[thread_num * 8 + 4], + temp[thread_num * 8 + 5], + temp[thread_num * 8 + 6], + temp[thread_num * 8 + 7]); + + pick_timer(start, local_timing[4]); + + memoryBarrierShared(); + barrier(); + + pick_timer(start, local_timing[5]); + + // Vertical DCT one row (so 64 columns). + uint row_offset = gl_LocalInvocationID.y * 64 + gl_LocalInvocationID.x; + idct_1d(temp[row_offset + 0 * 8], + temp[row_offset + 1 * 8], + temp[row_offset + 2 * 8], + temp[row_offset + 3 * 8], + temp[row_offset + 4 * 8], + temp[row_offset + 5 * 8], + temp[row_offset + 6 * 8], + temp[row_offset + 7 * 8]); + + pick_timer(start, local_timing[6]); + + uint y = block_row * 16 + block_y * 8; + uint x = block_x * 64 + gl_LocalInvocationID.y * 8 + gl_LocalInvocationID.x; + for (uint yl = 0; yl < 8; ++yl) { + imageStore(out_tex, ivec2(x, yl + y), vec4(temp[row_offset + yl * 8], 0.0, 0.0, 1.0)); + } + + pick_timer(start, local_timing[7]); + + memoryBarrierShared(); // is this needed? + barrier(); + + pick_timer(start, local_timing[8]); + pick_timer(start, local_timing[9]); // should be nearly nothing + } + +#if ENABLE_TIMING + for (int timer_idx = 0; timer_idx < 10; ++timer_idx) { + uint global_idx = thread_num * 10 + timer_idx; + + uint old_val = atomicAdd(timing[global_idx].x, local_timing[timer_idx].x); + if (old_val + local_timing[timer_idx].x < old_val) { + ++local_timing[timer_idx].y; + } + atomicAdd(timing[global_idx].y, local_timing[timer_idx].y); + } +#endif +} diff --git a/narabu.cpp b/narabu.cpp new file mode 100644 index 0000000..4897366 --- /dev/null +++ b/narabu.cpp @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +using namespace std; + +#define WIDTH 1280 +#define HEIGHT 720 + +const unsigned prob_bits = 12; +const unsigned prob_scale = 1 << prob_bits; +const unsigned NUM_SYMS = 256; +const unsigned NUM_TABLES = 16; + +struct RansDecSymbol { + unsigned sym_start; + unsigned sym_freq; +}; +struct RansDecodeTable { + int cum2sym[prob_scale]; + RansDecSymbol dsyms[NUM_SYMS]; +}; +RansDecodeTable decode_tables[NUM_TABLES]; + +optional read_varint(const char **ptr, const char *end) +{ + uint32_t x = 0; + int shift = 0; + while (*ptr < end) { + int ch = **ptr; + ++(*ptr); + + x |= (ch & 0x7f) << shift; + if ((ch & 0x80) == 0) return x; + shift += 7; + if (shift >= 32) { + return nullopt; // Error: Overlong int. + } + } + return nullopt; // Error: EOF. +} + +struct CoeffStream { + uint src_offset, src_len, sign_offset, sign_len, extra_bits; +}; +CoeffStream streams[45 * 64]; // HACK + +int main(int argc, char **argv) +{ + // Set up an OpenGL context using SDL. + if (SDL_Init(SDL_INIT_VIDEO) == -1) { + fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); + exit(1); + } + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); + + SDL_Window *window = SDL_CreateWindow("OpenGL window for unit test", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 32, 32, + SDL_WINDOW_OPENGL); + SDL_GLContext context = SDL_GL_CreateContext(window); + assert(context != nullptr); + + //char buf[16] = { 0 }; + + GLint size; + glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &size); + printf("shared_memory_size=%u\n", size); + + string shader_src = read_file("decoder-pre-sign.shader"); + GLuint shader_num = compile_shader(shader_src, GL_COMPUTE_SHADER); + GLuint glsl_program_num = glCreateProgram(); + glAttachShader(glsl_program_num, shader_num); + glLinkProgram(glsl_program_num); + + GLint success; + glGetProgramiv(glsl_program_num, GL_LINK_STATUS, &success); + if (success == GL_FALSE) { + GLchar error_log[1024] = {0}; + glGetProgramInfoLog(glsl_program_num, 1024, nullptr, error_log); + fprintf(stderr, "Error linking program: %s\n", error_log); + exit(1); + } + + glUseProgram(glsl_program_num); + + string coded = read_file(argc >= 2 ? argv[1] : "coded.dat"); + const char *ptr = &coded[0]; + const char *end = ptr + coded.size(); + +// printf("first few bytes offs=%zu: %d %d %d %d %d %d %d %d\n", ptr - coded.data(), +// (uint8_t)ptr[0], (uint8_t)ptr[1], (uint8_t)ptr[2], (uint8_t)ptr[3], +// (uint8_t)ptr[4], (uint8_t)ptr[5], (uint8_t)ptr[6], (uint8_t)ptr[7]); + + // read the rANS tables + for (unsigned table = 0; table < NUM_TABLES; ++table) { + uint32_t cum_freq = 0; + for (unsigned sym = 0; sym < NUM_SYMS; ++sym) { + optional freq = read_varint(&ptr, end); + if (!freq) { + fprintf(stderr, "Error parsing varint for table %d symbol %d\n", table, sym); + exit(1); + } + + decode_tables[table].dsyms[sym].sym_start = cum_freq; + decode_tables[table].dsyms[sym].sym_freq = *freq; + for (uint32_t i = 0; i < freq; ++i) { + decode_tables[table].cum2sym[cum_freq++] = sym; + } + } + } + + // Make cum2sym texture. + unique_ptr cum2sym_data(new uint8_t[prob_scale * NUM_TABLES]); + for (unsigned table = 0; table < NUM_TABLES; ++table) { + for (unsigned i = 0; i < prob_scale; ++i) { + cum2sym_data[prob_scale * table + i] = decode_tables[table].cum2sym[i]; + } + } + GLuint cum2sym_tex; + glGenTextures(1, &cum2sym_tex); + glBindTexture(GL_TEXTURE_2D, cum2sym_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, prob_scale, NUM_TABLES, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, cum2sym_data.get()); + + // Make dsyms texture. + unique_ptr[]> dsyms_data(new pair[NUM_SYMS * NUM_TABLES]); + for (unsigned table = 0; table < NUM_TABLES; ++table) { + for (unsigned sym = 0; sym < NUM_SYMS; ++sym) { + dsyms_data[NUM_SYMS * table + sym].first = decode_tables[table].dsyms[sym].sym_start; + dsyms_data[NUM_SYMS * table + sym].second = decode_tables[table].dsyms[sym].sym_freq; + } + } + GLuint dsyms_tex; + glGenTextures(1, &dsyms_tex); + glBindTexture(GL_TEXTURE_2D, dsyms_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16UI, NUM_SYMS, NUM_TABLES, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, dsyms_data.get()); + + GLuint out_tex; + glGenTextures(1, &out_tex); + glBindTexture(GL_TEXTURE_2D, out_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1280, 720, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 1280, 720, 0, GL_RED, GL_FLOAT, nullptr); + + //GLint src_offset_pos = glGetUniformLocation(glsl_program_num, "src_offset"); + //GLint sign_offset_pos = glGetUniformLocation(glsl_program_num, "sign_offset"); + //GLint extra_bits_pos = glGetUniformLocation(glsl_program_num, "extra_bits"); + GLint cum2sym_tex_pos = glGetUniformLocation(glsl_program_num, "cum2sym_tex"); + GLint dsyms_tex_pos = glGetUniformLocation(glsl_program_num, "dsyms_tex"); + GLint out_tex_pos = glGetUniformLocation(glsl_program_num, "out_tex"); + printf("%d err=0x%x pos=%d,%d,%d\n", __LINE__, glGetError(), cum2sym_tex_pos, dsyms_tex_pos, out_tex_pos); + + // Bind the textures. + glUniform1i(cum2sym_tex_pos, 0); + glUniform1i(dsyms_tex_pos, 1); + glUniform1i(out_tex_pos, 2); + glBindImageTexture(0, cum2sym_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8UI); + glBindImageTexture(1, dsyms_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RG16UI); + glBindImageTexture(2, out_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8); + printf("%d err=0x%x\n", __LINE__, glGetError()); + + // Decode all luma blocks. + unsigned num_blocks = (HEIGHT / 16); + for (unsigned y = 0; y < 8; ++y) { + for (unsigned x = 0; x < 8; ++x) { + unsigned coeff_num = y * 8 + x; + + for (unsigned yb = 0; yb < HEIGHT; yb += 16) { + optional num_rans_bytes = read_varint(&ptr, end); + if (!num_rans_bytes) { + fprintf(stderr, "Error parsing varint for block %d rANS bytes\n", yb); + exit(1); + } + + CoeffStream *stream = &streams[coeff_num * num_blocks + (yb/16)]; + stream->src_offset = ptr - coded.data(); + stream->src_len = *num_rans_bytes; + + // TODO: check len + ptr += *num_rans_bytes; + + optional num_sign_bytes = read_varint(&ptr, end); + if (!num_sign_bytes) { + fprintf(stderr, "Error parsing varint for block %d rANS bytes\n", yb); + exit(1); + } + + stream->sign_offset = ptr - coded.data(); + stream->sign_len = *num_sign_bytes >> 3; + stream->extra_bits = *num_sign_bytes & 0x7; + + // TODO: check len + // TODO: free bits + ptr += *num_sign_bytes >> 3; + + //printf("read %d rANS bytes, %d sign bytes\n", *num_rans_bytes, *num_sign_bytes); + } + } + } + + // put the coded data (as a whole) into an SSBO + printf("%d err=0x%x bufsize=%zu\n", __LINE__, glGetError(), coded.size()); + + GLuint ssbo_stream, ssbo, ssbo_out; + + glGenBuffers(1, &ssbo_stream); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_stream); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(streams), streams, GL_STREAM_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo_stream); + printf("%d err=0x%x bufsize=%zu\n", __LINE__, glGetError(), coded.size()); + + glGenBuffers(1, &ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, coded.size(), coded.data(), GL_STREAM_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 9, ssbo); + printf("%d err=0x%x bufsize=%zu\n", __LINE__, glGetError(), coded.size()); + + glGenBuffers(1, &ssbo_out); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_out); + glBufferData(GL_SHADER_STORAGE_BUFFER, 16384, nullptr, GL_STREAM_DRAW); // ?? + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, ssbo_out); + + for (int i = 0; i < 10000; ++i) + glDispatchCompute(1, 45, 1); + + unsigned *timing = (unsigned *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 16384, GL_MAP_READ_BIT); + //setlocale(LC_ALL, "nb_NO.UTF-8"); + + string phases[] = { + "init", + "loop overhead", + "rANS decode", + "barrier after rANS decode", + "horizontal IDCT", + "barrier after horizontal IDCT", + "vertical IDCT", + "store to texture", + "barrier after store to texture", + "dummy timer for overhead measurement", + }; + printf("\n"); + for (int i = 0; i < 10; ++i) { + //printf("%d: %'18.0f [%s]\n", i, double((uint64_t(timing[i * 2 + 1]) << 32) | timing[i * 2]), phases[i].c_str()); + printf("%d,%s", i, phases[i].c_str()); + for (int j = 0; j < 64; ++j) { + int idx = (j * 10 + i) * 2; + uint64_t val = (uint64_t(timing[idx + 1]) << 32) | timing[idx]; + // printf(" %'18.0f", double(val)); + // printf(" %'6.0f", double(val) * 1e-6); + printf(",%.0f", double(val) * 1e-6); + } + printf("\n"); + //printf(" [%s]\n", phases[i].c_str()); + } + printf("\n"); + + unsigned char *data = new unsigned char[1280 * 720]; + glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_UNSIGNED_BYTE, data); + printf("%d err=0x%x bufsize=%zu\n", __LINE__, glGetError(), coded.size()); + +#if 0 + for (int k = 0; k < 4; ++k) { + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 8; ++x) { + printf("%3d ", data[y * 1280 + x + k*8]); + } + printf("\n"); + } + printf("\n"); + } + printf("\n"); +#else + for (int k = 0; k < 4; ++k) { + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 8; ++x) { + //printf("%5.2f ", data[(y+8) * 1280 + x + (1272-k*8)]); + printf("%3d ", data[y * 1280 + x + k*8]); + } + printf("\n"); + } + printf("\n"); + } + printf("\n"); +#endif + + FILE *fp = fopen("narabu.pgm", "wb"); + fprintf(fp, "P5\n1280 720\n255\n"); + for (int y = 0; y < 720; ++y) { + for (int x = 0; x < 1280; ++x) { + int k = lrintf(data[y * 1280 + x]); + if (k < 0) k = 0; + if (k > 255) k = 255; + putc(k, fp); + } + } + fclose(fp); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // unbind + + printf("foo = 0x%x\n", glGetError()); +} diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..5749f63 --- /dev/null +++ b/util.cpp @@ -0,0 +1,75 @@ +#include +#include +#include + +#include "util.h" + +using namespace std; + +string read_file(const string &filename) +{ + const string full_pathname = filename; + + FILE *fp = fopen(full_pathname.c_str(), "r"); + if (fp == NULL) { + perror(full_pathname.c_str()); + exit(1); + } + + int ret = fseek(fp, 0, SEEK_END); + if (ret == -1) { + perror("fseek(SEEK_END)"); + exit(1); + } + + int size = ftell(fp); + + ret = fseek(fp, 0, SEEK_SET); + if (ret == -1) { + perror("fseek(SEEK_SET)"); + exit(1); + } + + string str; + str.resize(size); + ret = fread(&str[0], size, 1, fp); + if (ret == -1) { + perror("fread"); + exit(1); + } + if (ret == 0) { + fprintf(stderr, "Short read when trying to read %d bytes from %s\n", + size, full_pathname.c_str()); + exit(1); + } + fclose(fp); + + return str; +} + +GLuint compile_shader(const string &shader_src, GLenum type) +{ + GLuint obj = glCreateShader(type); + const GLchar* source[] = { shader_src.data() }; + const GLint length[] = { (GLint)shader_src.size() }; + glShaderSource(obj, 1, source, length); + glCompileShader(obj); + + GLchar info_log[4096]; + GLsizei log_length = sizeof(info_log) - 1; + glGetShaderInfoLog(obj, log_length, &log_length, info_log); + info_log[log_length] = 0; + if (strlen(info_log) > 0) { + fprintf(stderr, "Shader compile log: %s\n", info_log); + } + + GLint status; + glGetShaderiv(obj, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + fprintf(stderr, "Failed to compile shader: %s\n", shader_src.c_str()); + exit(1); + } + + return obj; +} + diff --git a/util.h b/util.h new file mode 100644 index 0000000..ebd416a --- /dev/null +++ b/util.h @@ -0,0 +1,15 @@ +#ifndef _UTIL_H +#define _UTIL_H 1 + +#include + +#include + +// Read a file from disk and return its contents. +// Dies if the file does not exist. +std::string read_file(const std::string &filename); + +GLuint compile_shader(const std::string &shader_src, GLenum type); + +#endif // !defined(_UTIL_H) + -- 2.39.2