فهرست منبع

GL: start with pass implementation

Andre Weissflog 8 سال پیش
والد
کامیت
ed3f3f6f47
3فایلهای تغییر یافته به همراه220 افزوده شده و 15 حذف شده
  1. 51 2
      _sokol_gfx.impl.h
  2. 159 11
      _sokol_gfx_gl.impl.h
  3. 10 2
      sokol_gfx.h

+ 51 - 2
_sokol_gfx.impl.h

@@ -233,6 +233,21 @@ void sg_init_vertex_step(sg_pipeline_desc* desc, int input_layout, sg_step_func
     layout->step_rate = step_rate;
 }
 
+void sg_init_pass_desc(sg_pass_desc* desc) {
+    SOKOL_ASSERT(desc);
+    desc->_init_guard = _SG_INIT_GUARD;
+    sg_attachment_desc* att_desc = &desc->depth_stencil_attachment;
+    att_desc->image = SG_INVALID_ID;
+    att_desc->mip_level = 0;
+    att_desc->slice = 0;
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        att_desc = &desc->color_attachments[i];
+        att_desc->image = SG_INVALID_ID;
+        att_desc->mip_level = 0;
+        att_desc->slice = 0;
+    }
+}
+
 void sg_init_pass_action(sg_pass_action* pa) {
     SOKOL_ASSERT(pa);
     pa->_init_guard = _SG_INIT_GUARD;
@@ -357,6 +372,12 @@ static bool _sg_is_valid_rendertarget_depth_format(sg_pixel_format fmt) {
     }
 }
 
+/* return true if pixel format is a depth-stencil format */
+static bool _sg_is_depth_stencil_format(sg_pixel_format fmt) {
+    /* FIXME: more depth stencil formats? */
+    return (SG_PIXELFORMAT_DEPTHSTENCIL == fmt);
+}
+
 /*-- resource pool slots (must be defined before rendering backend) ----------*/
 typedef struct {
     sg_id id;
@@ -776,7 +797,7 @@ static void _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) {
 }
 
 static void _sg_validate_pass_desc(const sg_pass_desc* desc) {
-    // FIXME
+    SOKOL_ASSERT(desc->color_attachments[0].image != SG_INVALID_ID);
 }
 
 static void _sg_validate_draw_state(const sg_draw_state* ds) {
@@ -907,7 +928,26 @@ void sg_init_pass(sg_id pass_id, const sg_pass_desc* desc) {
     _sg_validate_pass_desc(desc);
     _sg_pass* pass = _sg_lookup_pass(&_sg->pools, pass_id);
     SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC);
-    _sg_create_pass(&_sg->backend, pass, desc);
+    /* lookup pass attachment image pointers */
+    _sg_image* att_imgs[SG_MAX_COLOR_ATTACHMENTS + 1];
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        if (desc->color_attachments[i].image) {
+            att_imgs[i] = _sg_lookup_image(&_sg->pools, desc->color_attachments[i].image);
+            SOKOL_ASSERT(att_imgs[i] && att_imgs[i]->slot.state == SG_RESOURCESTATE_VALID);
+        }
+        else {
+            att_imgs[i] = 0;
+        }
+    }
+    const int ds_att_index = SG_MAX_COLOR_ATTACHMENTS;
+    if (desc->depth_stencil_attachment.image) {
+        att_imgs[ds_att_index] = _sg_lookup_image(&_sg->pools, desc->depth_stencil_attachment.image);
+        SOKOL_ASSERT(att_imgs[ds_att_index] && att_imgs[ds_att_index]->slot.state == SG_RESOURCESTATE_VALID);
+    }
+    else {
+        att_imgs[ds_att_index] = 0;
+    }
+    _sg_create_pass(&_sg->backend, pass, att_imgs, desc);
     SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID)||(pass->slot.state == SG_RESOURCESTATE_FAILED)); 
 }
 
@@ -994,6 +1034,15 @@ void sg_destroy_pipeline(sg_id pip_id) {
     }
 }
 
+void sg_destroy_pass(sg_id pass_id) {
+    SOKOL_ASSERT(_sg);
+    _sg_pass* pass = _sg_lookup_pass(&_sg->pools, pass_id);
+    if (pass) {
+        _sg_destroy_pass(&_sg->backend, pass);
+        _sg_pool_free_id(&_sg->pools.pool[SG_RESOURCETYPE_PASS], pass_id);
+    }
+}
+
 void sg_begin_pass(sg_id pass_id, const sg_pass_action* pass_action, int width, int height) {
     SOKOL_ASSERT(_sg && pass_action);
     SOKOL_ASSERT(pass_action->_init_guard == _SG_INIT_GUARD);

+ 159 - 11
_sokol_gfx_gl.impl.h

@@ -567,13 +567,38 @@ static void _sg_init_pipeline(_sg_pipeline* pip) {
     _sg_init_rasterizer_state(&pip->rast);
 }
 
+typedef struct {
+    _sg_image* image;
+    sg_id image_id;
+    int mip_level;
+    int slice;
+    GLuint gl_msaa_resolve_buffer;
+} _sg_attachment;
+
+static void _sg_init_attachment(_sg_attachment* att) {
+    SOKOL_ASSERT(att);
+    att->image = 0;
+    att->image_id = SG_INVALID_ID;
+    att->mip_level = 0;
+    att->slice = 0;
+    att->gl_msaa_resolve_buffer = 0;
+}
+
 typedef struct {
     _sg_slot slot;
+    GLuint gl_fb;
+    _sg_attachment color_atts[SG_MAX_COLOR_ATTACHMENTS];
+    _sg_attachment ds_att;
 } _sg_pass;
 
 static void _sg_init_pass(_sg_pass* pass) {
     SOKOL_ASSERT(pass);
     _sg_init_slot(&pass->slot);
+    pass->gl_fb = 0;
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        _sg_init_attachment(&pass->color_atts[i]);
+    }
+    _sg_init_attachment(&pass->ds_att);
 }
 
 /*-- state cache implementation ----------------------------------------------*/
@@ -711,7 +736,7 @@ static bool _sg_query_feature(_sg_backend* state, sg_feature f) {
 
 /*-- GL backend resource creation and destruction ----------------------------*/
 static void _sg_create_buffer(_sg_backend* state, _sg_buffer* buf, const sg_buffer_desc* desc) {
-    SOKOL_ASSERT(buf && desc);
+    SOKOL_ASSERT(state && buf && desc);
     SOKOL_ASSERT(buf->slot.state == SG_RESOURCESTATE_ALLOC);
     SOKOL_ASSERT(desc->data_size <= desc->size);
     _SG_GL_CHECK_ERROR();
@@ -737,7 +762,7 @@ static void _sg_create_buffer(_sg_backend* state, _sg_buffer* buf, const sg_buff
 }
 
 static void _sg_destroy_buffer(_sg_backend* state, _sg_buffer* buf) {
-    SOKOL_ASSERT(buf);
+    SOKOL_ASSERT(state && buf);
     _SG_GL_CHECK_ERROR();
     for (int slot = 0; slot < buf->num_slots; slot++) {
         if (buf->gl_buf[slot]) {
@@ -769,8 +794,7 @@ static bool _sg_gl_valid_texture_format(_sg_backend* state, sg_pixel_format fmt)
 }
 
 static void _sg_create_image(_sg_backend* state, _sg_image* img, const sg_image_desc* desc) {
-    SOKOL_ASSERT(state);
-    SOKOL_ASSERT(img && desc);
+    SOKOL_ASSERT(state && img && desc);
     SOKOL_ASSERT(img->slot.state == SG_RESOURCESTATE_ALLOC);
     _SG_GL_CHECK_ERROR();
     img->type = desc->type;
@@ -939,7 +963,7 @@ static void _sg_create_image(_sg_backend* state, _sg_image* img, const sg_image_
 }
 
 static void _sg_destroy_image(_sg_backend* state, _sg_image* img) {
-    SOKOL_ASSERT(img);
+    SOKOL_ASSERT(state && img);
     _SG_GL_CHECK_ERROR();
     for (int slot = 0; slot < img->num_slots; slot++) {
         if (img->gl_tex[slot]) {
@@ -982,7 +1006,7 @@ static GLuint _sg_compile_shader(sg_shader_stage stage, const char* src) {
 }
 
 static void _sg_create_shader(_sg_backend* state, _sg_shader* shd, const sg_shader_desc* desc) {
-    SOKOL_ASSERT(shd && desc);
+    SOKOL_ASSERT(state && shd && desc);
     SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_ALLOC);
     SOKOL_ASSERT(!shd->gl_prog);
     _SG_GL_CHECK_ERROR();
@@ -1055,7 +1079,7 @@ static void _sg_create_shader(_sg_backend* state, _sg_shader* shd, const sg_shad
 }
 
 static void _sg_destroy_shader(_sg_backend* state, _sg_shader* shd) {
-    SOKOL_ASSERT(shd);
+    SOKOL_ASSERT(state && shd);
     _SG_GL_CHECK_ERROR();
     if (shd->gl_prog) {
         glDeleteShader(shd->gl_prog);
@@ -1127,11 +1151,135 @@ static void _sg_destroy_pipeline(_sg_backend* state, _sg_pipeline* pip) {
     _sg_init_pipeline(pip);
 }
 
-static void _sg_create_pass(_sg_backend* state, _sg_pass* pass, const sg_pass_desc* desc) {
-    SOKOL_ASSERT(pass && desc);
+/*
+    _sg_create_pass
+
+    att_imgs must point to a _sg_image* att_imgs[SG_MAX_COLOR_ATTACHMENTS+1] array,
+    first entries are the color attachment images (or nullptr), last entry
+    is the depth-stencil image (or nullptr).
+*/
+static void _sg_create_pass(_sg_backend* state, _sg_pass* pass, _sg_image** att_images, const sg_pass_desc* desc) {
+    SOKOL_ASSERT(pass && att_images && desc);
     SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_ALLOC);
-    /* FIXME */
-    pass->slot.state = SG_RESOURCESTATE_FAILED;
+    SOKOL_ASSERT(att_images && att_images[0]);
+    _SG_GL_CHECK_ERROR();
+
+    /* copy image pointers and desc attributes */
+    const sg_attachment_desc* att_desc;
+    _sg_attachment* att;
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        SOKOL_ASSERT(0 == pass->color_atts[i].image);
+        att_desc = &desc->color_attachments[i];
+        if (att_desc->image != SG_INVALID_ID) {
+            SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image));
+            att = &pass->color_atts[i];
+            SOKOL_ASSERT((att->image == 0) && (att->image_id == SG_INVALID_ID));
+            att->image = att_images[i];
+            att->image_id = att_desc->image;
+            att->mip_level = att_desc->mip_level;
+            att->slice = att_desc->slice;
+        }
+    }
+    SOKOL_ASSERT(0 == pass->ds_att.image);
+    att_desc = &desc->depth_stencil_attachment;
+    const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS;
+    if (att_desc->image != SG_INVALID_ID) {
+        SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image));
+        att = &pass->ds_att;
+        SOKOL_ASSERT((att->image == 0) && (att->image_id == SG_INVALID_ID));
+        att->image = att_images[ds_img_index];
+        att->image_id = att_desc->image;
+        att->mip_level = att_desc->mip_level;
+        att->slice = att_desc->slice;
+    }
+
+    /* store current framebuffer binding (restored at end of function) */
+    GLint gl_orig_fb;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_orig_fb);
+
+    /* create a framebuffer object */
+    glGenFramebuffers(1, &pass->gl_fb);
+    glBindFramebuffer(GL_FRAMEBUFFER, pass->gl_fb);
+
+    /* attach msaa render buffer or textures */
+    const bool is_msaa = (0 != att_images[0]->gl_msaa_render_buffer);
+    if (is_msaa) {
+        for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+            const _sg_image* att_img = pass->color_atts[i].image;
+            if (att_img) {
+                const GLuint gl_render_buffer = att_img->gl_msaa_render_buffer;
+                SOKOL_ASSERT(gl_render_buffer);
+                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, gl_render_buffer);
+            }
+        }
+    }
+    else {
+        for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+            const _sg_image* att_img = pass->color_atts[i].image;
+            const int mip_level = pass->color_atts[i].mip_level;
+            const int slice = pass->color_atts[i].slice;
+            if (att_img) {
+                const GLuint gl_tex = att_img->gl_tex[0];
+                SOKOL_ASSERT(gl_tex);
+                const GLenum gl_att = GL_COLOR_ATTACHMENT0 + i;
+                switch (att_img->type) {
+                    case SG_IMAGETYPE_2D:
+                        glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, GL_TEXTURE_2D, gl_tex, mip_level);
+                        break;
+                    case SG_IMAGETYPE_CUBE:
+                        glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, _sg_gl_cubeface_target(slice), gl_tex, mip_level);
+                        break;
+                    default:
+                        /* 3D- or array-texture */
+                        #if !defined(ORYOL_USE_GLES2)
+                        glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_att, gl_tex, mip_level, slice);
+                        #endif
+                        break;
+                }
+            }
+        }
+    }
+    /* attach depth-stencil buffer to framebuffer */
+    if (pass->ds_att.image) {
+        const GLuint gl_render_buffer = pass->ds_att.image->gl_depth_render_buffer;
+        SOKOL_ASSERT(gl_render_buffer);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer);
+        if (_sg_is_depth_stencil_format(pass->ds_att.image->depth_format)) {
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer);
+        }
+    }
+
+    /* check if framebuffer is complete */
+    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+        SOKOL_LOG("Framebuffer completeness check failed!\n");
+        pass->slot.state = SG_RESOURCESTATE_FAILED;
+        return;
+    }
+    
+    /* FIXME: MSAA resolve buffers */
+
+    /* restore original framebuffer binding */
+    glBindFramebuffer(GL_FRAMEBUFFER, gl_orig_fb);
+    _SG_GL_CHECK_ERROR();
+    pass->slot.state = SG_RESOURCESTATE_VALID;
+}
+
+static void _sg_destroy_pass(_sg_backend* state, _sg_pass* pass) {
+    SOKOL_ASSERT(state && pass);
+    _SG_GL_CHECK_ERROR();
+    if (0 != pass->gl_fb) {
+        glDeleteFramebuffers(1, &pass->gl_fb);
+    }
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        if (pass->color_atts[i].gl_msaa_resolve_buffer) {
+            glDeleteFramebuffers(1, &pass->color_atts[i].gl_msaa_resolve_buffer);
+        }
+    }
+    if (pass->ds_att.gl_msaa_resolve_buffer) {
+        glDeleteFramebuffers(1, &pass->ds_att.gl_msaa_resolve_buffer);
+    }
+    _SG_GL_CHECK_ERROR();
+    _sg_init_pass(pass);
 }
 
 /*-- GL backend rendering functions ------------------------------------------*/

+ 10 - 2
sokol_gfx.h

@@ -475,9 +475,16 @@ typedef struct {
     sg_rasterizer_state rast;
 } sg_pipeline_desc;
 
+typedef struct {
+    sg_id image;
+    uint16_t mip_level;
+    uint16_t slice;
+} sg_attachment_desc;
+
 typedef struct {
     uint32_t _init_guard;
-    /* FIXME */
+    sg_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS];
+    sg_attachment_desc depth_stencil_attachment;
 } sg_pass_desc;
 
 typedef struct {
@@ -491,7 +498,6 @@ typedef struct {
 
 /* struct initializers */
 extern void sg_init_desc(sg_desc* desc);
-extern void sg_init_pass_action(sg_pass_action* pa);
 extern void sg_init_buffer_desc(sg_buffer_desc* desc);
 extern void sg_init_image_desc(sg_image_desc* desc);
 extern void sg_init_shader_desc(sg_shader_desc* desc);
@@ -501,6 +507,8 @@ extern void sg_init_pipeline_desc(sg_pipeline_desc* desc);
 extern void sg_init_named_vertex_attr(sg_pipeline_desc* desc, int input_layout, const char* name, sg_vertex_format format);
 extern void sg_init_indexed_vertex_attr(sg_pipeline_desc* desc, int input_layout, int attr_index, sg_vertex_format format);
 extern void sg_init_vertex_step(sg_pipeline_desc* desc, int input_layout, sg_step_func step_func, int step_rate);
+extern void sg_init_pass_desc(sg_pass_desc* desc);
+extern void sg_init_pass_action(sg_pass_action* pa);
 extern void sg_init_draw_state(sg_draw_state* ds);
 
 /* setup */