Feat[basevertex,shader]: Reimnplement basevertex rendering on top of indirect rendering. Make Iris be able to run shaders.

This commit is contained in:
artdeell 2024-06-24 13:02:40 +03:00 committed by artdeell
parent bd89a868cc
commit 600342d99a
7 changed files with 66 additions and 190 deletions

View File

@ -6,93 +6,25 @@
#include "egl.h"
#include "main.h"
const GLchar*const basevertex_offset_shader =
"#version 310 es\n"
"layout(std430) buffer;\n"
"layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;\n"
"layout(binding = 0) readonly buffer sourceBuffer {\n"
" uint src_elements[];\n"
"};\n"
"layout(binding = 1) writeonly buffer destinationBuffer {\n"
" uint dst_elements[];\n"
"};\n"
"layout(binding = 2) readonly buffer dataBuffer {\n"
" uint baseVertex;\n"
" uint elementCount;\n"
" uint inputBitWidth;\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint ident = gl_GlobalInvocationID.x;\n"
" uint inputByteWidth = (uint(32) / inputBitWidth);\n"
" uint ident_src = ident / inputByteWidth;\n"
" dst_elements[ident] = bitfieldExtract(src_elements[ident_src], int((ident % inputByteWidth) * inputBitWidth), int(inputBitWidth)) + baseVertex;\n"
"}\n";
typedef struct {
GLuint baseVertex;
GLuint elementCount;
GLuint inputBitWidth;
} data_buffer_t;
GLuint count;
GLuint instanceCount;
GLuint firstIndex;
GLint baseVertex;
GLuint reservedMustBeZero;
} indirect_pass_t;
void basevertex_init(context_t* context) {
basevertex_renderer_t *renderer = &context->basevertex;
while(es3_functions.glGetError() != 0) {}
GLuint offset_shader = es3_functions.glCreateShader(GL_COMPUTE_SHADER);
es3_functions.glShaderSource(offset_shader, 1, &basevertex_offset_shader, NULL);
es3_functions.glCompileShader(offset_shader);
GLint comp_status;
es3_functions.glGetShaderiv(offset_shader, GL_COMPILE_STATUS, &comp_status);
if(comp_status != GL_TRUE) {
GLchar infolog[2049];
es3_functions.glGetShaderInfoLog(offset_shader, 2048, NULL, infolog);
printf("tinywrapper: Failed to compile compute shader: %s\n", infolog);
es3_functions.glDeleteShader(offset_shader);
return;
}
renderer->computeProgram = es3_functions.glCreateProgram();
es3_functions.glAttachShader(renderer->computeProgram, offset_shader);
es3_functions.glLinkProgram(renderer->computeProgram);
es3_functions.glDeleteShader(offset_shader);
es3_functions.glGetProgramiv(renderer->computeProgram, GL_LINK_STATUS, &comp_status);
if(comp_status != GL_TRUE) {
GLchar infolog[2049];
es3_functions.glGetProgramInfoLog(renderer->computeProgram, 2048, NULL, infolog);
printf("tinywrapper: Failed to link compute program: %s\n", infolog);
es3_functions.glDeleteProgram(offset_shader);
return;
}
es3_functions.glGenBuffers(1, &renderer->indirectRenderBuffer);
GLenum error = es3_functions.glGetError();
if(error != GL_NO_ERROR) {
printf("tinywrapper: Failed to initialize compute shader: %x\n", error);
return;
}
while(es3_functions.glGetError() != 0) {}
es3_functions.glGenBuffers(1, &renderer->computeIndexBuffer);
es3_functions.glGenBuffers(1, &renderer->computeMetaBuffer);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeMetaBuffer);
es3_functions.glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data_buffer_t), NULL, GL_DYNAMIC_DRAW);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
error = es3_functions.glGetError();
if(error != GL_NO_ERROR) {
printf("tinywrapper: Failed to initialize compute buffers: %x\n", error);
printf("tinywrapper: Failed to initialize indirect buffers: %x\n", error);
return;
}
renderer->ready = true;
}
GLint type_bits(GLenum type) {
switch (type) {
case GL_UNSIGNED_BYTE: return 8;
case GL_UNSIGNED_SHORT: return 16;
case GL_UNSIGNED_INT: return 32;
default: return -1;
}
}
GLint type_bytes(GLenum type) {
switch (type) {
case GL_UNSIGNED_BYTE: return 1;
@ -102,50 +34,8 @@ GLint type_bytes(GLenum type) {
}
}
static void restore_state(GLuint element_buffer) {
unordered_map* ssbos = current_context->bound_basebuffers[get_base_buffer_index(GL_SHADER_STORAGE_BUFFER)];
if(unordered_map_size(ssbos) != 0) {
unordered_map_iterator iterator;
unordered_map_iterator_alloc_local(ssbos, &iterator);
void *k;
basebuffer_binding_t *v;
while(unordered_map_iterator_next(&iterator, &k, (void*)&v)) {
if(v->ranged) es3_functions.glBindBufferRange(GL_SHADER_STORAGE_BUFFER, (GLuint)k, v->buffer, v->offset, v->size);
else es3_functions.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, (GLuint)k, v->buffer);
}
}
es3_functions.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, current_context->bound_buffers[get_buffer_index(GL_SHADER_STORAGE_BUFFER)]);
}
void glDrawElementsBaseVertex_inner(basevertex_renderer_t *renderer, GLenum mode,
GLsizei count,
GLenum type,
void *indices,
GLint basevertex,
GLuint elementbuffer) {
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeIndexBuffer);
es3_functions.glBufferData(GL_SHADER_STORAGE_BUFFER, count * (GLint)sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeMetaBuffer);
data_buffer_t buffer_info;
buffer_info.baseVertex = basevertex;
buffer_info.elementCount = count;
buffer_info.inputBitWidth = type_bits(type);
es3_functions.glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data_buffer_t), &buffer_info);
es3_functions.glUseProgram(renderer->computeProgram);
uintptr_t offset = (uintptr_t)indices;
es3_functions.glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, elementbuffer, (GLintptr)offset, count *
type_bytes(type));
es3_functions.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, renderer->computeIndexBuffer);
es3_functions.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, renderer->computeMetaBuffer);
es3_functions.glDispatchCompute((count + (256-1))/256, 1, 1);
es3_functions.glUseProgram(current_context->program);
es3_functions.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->computeIndexBuffer);
es3_functions.glDrawElements(mode, count, GL_UNSIGNED_INT, NULL);
es3_functions.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, current_context->bound_buffers[get_buffer_index(GL_DRAW_INDIRECT_BUFFER)]);
}
void glDrawElementsBaseVertex(GLenum mode,
@ -163,16 +53,27 @@ void glDrawElementsBaseVertex(GLenum mode,
printf("tinywrapper: Base vertex draws without element buffer are not supported\n");
return;
}
glDrawElementsBaseVertex_inner(renderer, mode, count, type, indices, basevertex, elementbuffer);
GLint typeBytes = type_bytes(type);
uintptr_t indicesPointer = (uintptr_t)indices;
if(indicesPointer % typeBytes != 0) {
printf("tinywrapper: misaligned base vertex draw not supported\n");
}
indirect_pass_t indirect_pass;
indirect_pass.count = count;
indirect_pass.firstIndex = indicesPointer / typeBytes;
indirect_pass.baseVertex = basevertex;
indirect_pass.instanceCount = 1;
indirect_pass.reservedMustBeZero = 0;
es3_functions.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, renderer->indirectRenderBuffer);
es3_functions.glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(indirect_pass_t), &indirect_pass, GL_STREAM_DRAW);
es3_functions.glDrawElementsIndirect(mode, type, 0);
restore_state(elementbuffer);
}
void glMultiDrawElementsBaseVertex(GLenum mode,
const GLsizei *count,
const GLsizei *count,
GLenum type,
const void * const *indices,
GLsizei drawcount,
@ -187,63 +88,25 @@ void glMultiDrawElementsBaseVertex(GLenum mode,
printf("tinywrapper: Base vertex draws without element buffer are not supported\n");
return;
}
GLint typeBytes = type_bytes(type);
indirect_pass_t indirect_passes[drawcount];
for(GLsizei i = 0; i < drawcount; i++) {
glDrawElementsBaseVertex_inner(renderer, mode, count[i], type, (void*)indices[i], basevertex[i], elementbuffer);
uintptr_t indicesPointer = (uintptr_t)indices[i];
if(indicesPointer % typeBytes != 0) {
printf("tinywrapper: misaligned base vertex draw not supported (draw %i)\n", i);
return;
}
indirect_pass_t* pass = &indirect_passes[i];
pass->count = count[i];
pass->firstIndex = indicesPointer / typeBytes;
pass->baseVertex = basevertex[i];
pass->instanceCount = 1;
pass->reservedMustBeZero = 0;
}
es3_functions.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, renderer->indirectRenderBuffer);
es3_functions.glBufferData(GL_DRAW_INDIRECT_BUFFER, (long)sizeof(indirect_pass_t) * drawcount, indirect_passes, GL_STREAM_DRAW);
for(GLsizei i = 0; i < drawcount; i++) {
es3_functions.glDrawElementsIndirect(mode, type, (void*)(sizeof(indirect_pass_t) * i));
}
restore_state(elementbuffer);
}
// TODO: Figure out how to fix the proper way of doing it
/*
static void render_out( basevertex_renderer_t *renderer, GLenum mode, GLsizei inserted_count) {
es3_functions.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->computeIndexBuffer);
es3_functions.glUseProgram(current_context->program);
es3_functions.glDrawElements(mode, inserted_count, GL_UNSIGNED_INT, NULL);
}
void glMultiDrawElementsBaseVertex( GLenum mode,
const GLsizei *count,
GLenum type,
const void * const *indices,
GLsizei drawcount,
const GLint *basevertex) {
if(!current_context) return;
basevertex_renderer_t *renderer = &current_context->basevertex;
if(!renderer->ready) return;
GLint elementbuffer;
es3_functions.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &elementbuffer);
if(elementbuffer == 0) {
// I am not bothered enough to implement this.
printf("tinywrapper: Base vertex draws without element buffer are not supported\n");
return;
}
GLsizei total_count = 0;
for (int i = 0; i < drawcount; i++) total_count += count[i];
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeIndexBuffer);
es3_functions.glBufferData(GL_SHADER_STORAGE_BUFFER, total_count * 4, NULL, GL_STREAM_DRAW);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeMetaBuffer);
es3_functions.glUseProgram(renderer->computeProgram);
es3_functions.glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, renderer->computeMetaBuffer, 0, sizeof(data_buffer_t));
data_buffer_t buffer_info;
buffer_info.inputBitWidth = type_bits(type);
GLint current_type_bytes = type_bytes(type);
GLsizei inserted_count = 0;
for (int i = 0; i < drawcount; i++) {
GLsizei local_count = count[i];
uintptr_t local_indices = (uintptr_t)indices[i];
GLint local_basevertex = basevertex[i];
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, renderer->computeMetaBuffer);
buffer_info.elementCount = local_count;
buffer_info.baseVertex = local_basevertex;
es3_functions.glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data_buffer_t), &buffer_info);
es3_functions.glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
es3_functions.glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, elementbuffer, (GLintptr)local_indices, local_count * current_type_bytes);
es3_functions.glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, renderer->computeIndexBuffer, inserted_count * 4, local_count * 4);
es3_functions.glDispatchCompute((local_count + (256-1))/256, 1, 1);
inserted_count += local_count;
}
render_out(renderer, mode, inserted_count);
restore_state(elementbuffer);
}*/
}

View File

@ -10,16 +10,14 @@
#include "proc.h"
#include "unordered_map/unordered_map.h"
#define MAX_BOUND_BUFFERS 8
#define MAX_BOUND_BUFFERS 9
#define MAX_BOUND_BASEBUFFERS 4
#define MAX_DRAWBUFFERS 8
#define MAX_FBTARGETS 8
typedef struct {
bool ready;
GLuint computeIndexBuffer;
GLuint computeMetaBuffer;
GLuint computeProgram;
GLuint indirectRenderBuffer;
} basevertex_renderer_t;
typedef struct {

View File

@ -1,4 +1,4 @@
// Added manually as needed
GLESFUNC(glDispatchCompute,PFNGLDISPATCHCOMPUTEPROC)
GLESFUNC(glDrawElementsIndirect,PFNGLDRAWELEMENTSINDIRECTPROC)
GLESFUNC(glMultiDrawArraysEXT,PFNGLMULTIDRAWARRAYSEXTPROC)
GLESFUNC(glMultiDrawElementsEXT,PFNGLMULTIDRAWELEMENTSEXTPROC)

View File

@ -21,6 +21,11 @@ void glMultiDrawElementsBaseVertex( GLenum mode,
void glBindFragDataLocation(GLuint program,
GLuint colorNumber,
const char * name);
void glGetTexImage( GLenum target,
GLint level,
GLenum format,
GLenum type,
void * pixels);
GLESOVERRIDE(glClearDepth)
GLESOVERRIDE(glMapBuffer)
@ -55,4 +60,5 @@ GLESOVERRIDE(glReadPixels)
GLESOVERRIDE(glTexSubImage2D)
GLESOVERRIDE(glCopyTexSubImage2D)
GLESOVERRIDE(glTexParameteri)
GLESOVERRIDE(glBindFragDataLocation)
GLESOVERRIDE(glBindFragDataLocation)
GLESOVERRIDE(glGetTexImage)

View File

@ -125,7 +125,7 @@ const GLubyte* glGetString(GLenum name) {
case GL_VERSION:
return (const GLubyte*)"3.0 tinywrapper";
case GL_SHADING_LANGUAGE_VERSION:
return (const GLubyte*)"150 tinywrapper";
return (const GLubyte*)"1.50 tinywrapper";
default:
return es3_functions.glGetString(name);
}
@ -146,6 +146,7 @@ int get_buffer_index(GLenum buffer) {
case GL_TRANSFORM_FEEDBACK_BUFFER: return 5;
case GL_UNIFORM_BUFFER: return 6;
case GL_SHADER_STORAGE_BUFFER: return 7;
case GL_DRAW_INDIRECT_BUFFER: return 8;
default: return -1;
}
}

View File

@ -47,8 +47,9 @@ static GLenum get_target_query_param(GLenum target) {
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return GL_TEXTURE_BINDING_CUBE_MAP;
default:
return GL_NONE;
}
return GL_NONE;
}
static void buffer_copier_release(GLenum target, GLint level, GLint x, GLint y, GLsizei w, GLsizei h) {
@ -66,6 +67,14 @@ static void buffer_copier_release(GLenum target, GLint level, GLint x, GLint y,
es3_functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, current_context->read_framebuffer);
}
void glGetTexImage( GLenum target,
GLint level,
GLenum format,
GLenum type,
void * pixels) {
printf("glGetTexImage(%x, %i, %x, %x, %p)\n", target, level, format, type, pixels);
}
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * data) {
if(!current_context) return;
if(format == GL_DEPTH_COMPONENT) {

View File

@ -125,7 +125,6 @@ void glLinkProgram(GLuint program) {
return;
fallthrough:
es3_functions.glLinkProgram(program);
return;
}
GLuint glCreateShader(GLenum shaderType) {
@ -171,7 +170,7 @@ void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, co
target_string[target_length] = 0;
#undef SRC_LEN
GLchar* new_source = optimize_shader(target_string, shader_info->shader_type == GL_VERTEX_SHADER, 330, 300);
GLchar* new_source = optimize_shader(target_string, shader_info->shader_type == GL_VERTEX_SHADER, 410, 300);
//printf("\n\n\nShader Result\n%s\n\n\n", new_source);
if(shader_info->source != NULL) free((void*)shader_info->source);
shader_info->source = new_source;