diff --git a/client/client_send.js b/client/client_send.js index fd4b826..5ce8b83 100644 --- a/client/client_send.js +++ b/client/client_send.js @@ -8,7 +8,7 @@ function serializer_create(size) { 'strview': new Uint8Array(buffer), 'need_gpu_allocate': true, // need to call glBufferData to create a GPU buffer of size serializer.size - 'gpu_upload_from': 0, // need to call glBufferSubData for bytes in [serializer.gpu_upload_from, serializer.offset) + 'gpu_upload_from': 0, // need to call glBufferSubData/glTexSubImage2D for bytes in [serializer.gpu_upload_from, serializer.offset) }; } diff --git a/client/webgl_draw.js b/client/webgl_draw.js index 479d819..06faa1a 100644 --- a/client/webgl_draw.js +++ b/client/webgl_draw.js @@ -25,26 +25,46 @@ function upload_if_needed(gl, buffer_kind, serializer) { } function upload_square_rgba16ui_texture(gl, serializer, texture_size) { - // TODO: only subupload what's needed - const bpp = 2 * 4; - const data_size = serializer.offset; - const data_pixels = data_size / bpp; // data_size % bpp is expected to always be zero here + const data_size = serializer.offset - serializer.gpu_upload_from; + + let data_pixels = data_size / bpp; // data_size % bpp is expected to always be zero here + + const pixels_already_uploaded = serializer.gpu_upload_from / bpp; + let rows_uploaded = Math.floor(pixels_already_uploaded / texture_size); + const rows_remainder = pixels_already_uploaded % texture_size; + + // Upload first non-whole row (if last upload was not a whole number of rows) + if (rows_remainder > 0) { + const row_upload_to_full = texture_size - rows_remainder; + const first_upload = Math.min(row_upload_to_full, data_pixels); + + if (first_upload > 0) { + gl.texSubImage2D(gl.TEXTURE_2D, 0, rows_remainder, rows_uploaded, first_upload, 1, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, new Uint16Array(serializer.buffer, serializer.gpu_upload_from, first_upload * 4)); + + data_pixels -= first_upload; + serializer.gpu_upload_from += first_upload; + rows_uploaded += 1; + } + } const rows = Math.ceil(data_pixels / texture_size); const last_row = data_pixels % texture_size; - const whole_upload = (rows - 1) * texture_size * bpp; + const whole_upload = (rows - 1) * texture_size; // Upload whole rows if (rows > 1) { - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, texture_size, rows - 1, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, new Uint16Array(serializer.buffer, 0, whole_upload / 2)); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, rows_uploaded, texture_size, rows - 1, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, new Uint16Array(serializer.buffer, serializer.gpu_upload_from, whole_upload * 4)); + rows_uploaded += rows - 1; } // Upload last row - if (last_row > 0) { + if (last_row > 0) { const last_row_upload = last_row * bpp; - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, rows - 1, last_row, 1, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, new Uint16Array(serializer.buffer, whole_upload, last_row_upload / 2)); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, rows_uploaded, last_row, 1, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, new Uint16Array(serializer.buffer, whole_upload, last_row_upload * 4)); } + + serializer.gpu_upload_from = serializer.offset; } function draw_html(state) {