Browse Source

MRT begin_pass, new begin_default_pass, new shader uniform declaration

Andre Weissflog 8 years ago
parent
commit
2b67a23a75
4 changed files with 189 additions and 72 deletions
  1. 6 0
      .gitignore
  2. 96 37
      _sokol_gfx.impl.h
  3. 77 30
      _sokol_gfx_gl.impl.h
  4. 10 5
      sokol_gfx.h

+ 6 - 0
.gitignore

@@ -0,0 +1,6 @@
+.vscode/
+#>fips
+# this area is managed by fips, do not edit
+.fips-*
+*.pyc
+#<fips

+ 96 - 37
_sokol_gfx.impl.h

@@ -87,19 +87,22 @@ void sg_init_image_desc(sg_image_desc* desc) {
 static void _sg_init_shader_stage_desc(sg_shader_stage_desc* desc) {
     SOKOL_ASSERT(desc);
     desc->source = 0;
+    desc->num_ubs = 0;
+    desc->num_images = 0;
     for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) {
         sg_shader_uniform_block_desc* ub_desc = &desc->ub[ub_index];
         ub_desc->size = 0;
+        ub_desc->num_uniforms = 0;
         for (int u_index = 0; u_index < SG_MAX_UNIFORMS; u_index++) {
             sg_shader_uniform_desc* u_desc = &ub_desc->u[u_index];
             u_desc->name = 0;
             u_desc->offset = 0;
             u_desc->type = SG_UNIFORMTYPE_INVALID;
-            u_desc->count = 1;
+            u_desc->array_count = 1;
         }
     }
     for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) {
-        sg_shader_image_desc* img_desc = &desc->images[img_index];
+        sg_shader_image_desc* img_desc = &desc->image[img_index];
         img_desc->name = 0;
         img_desc->type = SG_IMAGETYPE_INVALID;
     }
@@ -112,22 +115,32 @@ void sg_init_shader_desc(sg_shader_desc* desc) {
     _sg_init_shader_stage_desc(&desc->fs);
 }
 
-void sg_init_uniform_block(sg_shader_uniform_block_desc* desc, int ub_size) {
+void sg_init_uniform_block(sg_shader_desc* desc, sg_shader_stage stage, int ub_size) {
     SOKOL_ASSERT(desc);
+    SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS));
     SOKOL_ASSERT(ub_size > 0);
-    desc->size = ub_size;
+    sg_shader_stage_desc* s = (stage == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs;
+    SOKOL_ASSERT(s->num_ubs < SG_MAX_SHADERSTAGE_UBS);
+    SOKOL_ASSERT(s->ub[s->num_ubs].size == 0);
+    s->ub[s->num_ubs++].size = ub_size;
 }
 
-void sg_init_named_uniform(sg_shader_uniform_desc* desc, const char* name, int ub_offset, sg_uniform_type type, int array_count) {
+void sg_init_named_uniform(sg_shader_desc* desc, sg_shader_stage stage, const char* name, int ub_offset, sg_uniform_type type, int array_count) {
     SOKOL_ASSERT(desc);
+    SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS));
     SOKOL_ASSERT(name);
     SOKOL_ASSERT(ub_offset >= 0);
     SOKOL_ASSERT(type != SG_UNIFORMTYPE_INVALID);
     SOKOL_ASSERT(array_count >= 1);
-    desc->name = name;
-    desc->offset = ub_offset;
-    desc->type = type;
-    desc->count = array_count;
+    sg_shader_stage_desc* s = (stage == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs;
+    SOKOL_ASSERT(s->num_ubs >= 1);
+    sg_shader_uniform_block_desc* ub = &(s->ub[s->num_ubs-1]);
+    SOKOL_ASSERT(ub->num_uniforms < SG_MAX_UNIFORMS);
+    sg_shader_uniform_desc* u_desc = &(ub->u[ub->num_uniforms++]);
+    u_desc->name = name;
+    u_desc->offset = ub_offset;
+    u_desc->type = type;
+    u_desc->array_count = array_count;
 }
 
 static void _sg_init_vertex_layout_desc(sg_vertex_layout_desc* layout) {
@@ -751,34 +764,22 @@ static void _sg_validate_shader_desc(const sg_shader_desc* desc) {
     SOKOL_ASSERT(desc->fs.source);
     #endif
     #ifdef SOKOL_DEBUG
-    bool ub_range_valid = true;
     for (int i = 0; i < SG_NUM_SHADER_STAGES; i++) {
         const sg_shader_stage_desc* stage_desc = (i == 0)? &desc->vs : &desc->fs;
-        for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) {
+        SOKOL_ASSERT((stage_desc->num_ubs >= 0) && (stage_desc->num_ubs <= SG_MAX_SHADERSTAGE_UBS));
+        for (int ub_index = 0; ub_index < stage_desc->num_ubs; ub_index++) {
             const sg_shader_uniform_block_desc* ub_desc = &stage_desc->ub[ub_index];
-            if (ub_desc->size > 0) {
-                SOKOL_ASSERT(ub_range_valid);
-                bool u_range_valid = true;
-                for (int u_index = 0; u_index < SG_MAX_UNIFORMS; u_index++) {
-                    const sg_shader_uniform_desc* u_desc = &ub_desc->u[u_index];
-                    if (u_desc->type != SG_UNIFORMTYPE_INVALID) {
-                        SOKOL_ASSERT(u_range_valid);
-                        #ifdef SOKOL_USE_GLES2
-                        SOKOL_ASSERT(u_desc->name);
-                        #endif
-                        SOKOL_ASSERT(u_desc->count >= 1);
-                        SOKOL_ASSERT(u_desc->offset >= 0);
-                        SOKOL_ASSERT((u_desc->offset + _sg_uniform_size(u_desc->type, u_desc->count)) <= ub_desc->size);
-                    }
-                    else {
-                        /* uniforms must use consecutive slots */
-                        u_range_valid = false;
-                    }
-                }
-            }
-            else {
-                /* uniform blocks must use consecutive slots */
-                ub_range_valid = false;
+            SOKOL_ASSERT(ub_desc->size > 0);
+            SOKOL_ASSERT((ub_desc->num_uniforms > 0) && (ub_desc->num_uniforms <= SG_MAX_UNIFORMS));
+            for (int u_index = 0; u_index < ub_desc->num_uniforms; u_index++) {
+                const sg_shader_uniform_desc* u_desc = &ub_desc->u[u_index];
+                SOKOL_ASSERT(u_desc->type != SG_UNIFORMTYPE_INVALID);
+                #ifdef SOKOL_USE_GLES2
+                SOKOL_ASSERT(u_desc->name);
+                #endif
+                SOKOL_ASSERT(u_desc->array_count >= 1);
+                SOKOL_ASSERT(u_desc->offset >= 0);
+                SOKOL_ASSERT((u_desc->offset + _sg_uniform_size(u_desc->type, u_desc->array_count)) <= ub_desc->size);
             }
         }
     }
@@ -808,6 +809,54 @@ static void _sg_validate_draw_state(const sg_draw_state* ds) {
     SOKOL_ASSERT(ds->vertex_buffers[0]);    
 }
 
+static void _sg_validate_begin_pass(const _sg_pass* pass, const sg_pass_action* pass_action) {
+    SOKOL_ASSERT(pass && pass_action);
+    /* must have at least one color attachment */
+    SOKOL_ASSERT(pass->color_atts[0].image);
+    /* check color attachments */
+    #if defined(SOKOL_DEBUG)
+    const _sg_image* img = pass->color_atts[0].image;
+    bool img_continuous = true;
+    for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+        const _sg_attachment* att = &pass->color_atts[i];
+        if (att->image) {
+            SOKOL_ASSERT(img_continuous);
+            /* pass valid? */
+            SOKOL_ASSERT(att->image->slot.state == SG_RESOURCESTATE_VALID);
+            /* pass still exists? */
+            SOKOL_ASSERT(att->image->slot.id == att->image_id);
+            /* all images must be render target */
+            SOKOL_ASSERT(att->image->render_target);
+            /* all images must be immutable */
+            SOKOL_ASSERT(att->image->usage == SG_USAGE_IMMUTABLE);
+            /* all images must have same size */
+            SOKOL_ASSERT(att->image->width == img->width);
+            SOKOL_ASSERT(att->image->height == img->height);
+            /* all images must have same pixel format */
+            SOKOL_ASSERT(att->image->color_format == img->color_format);
+            /* must be a valid color render target pixel format */
+            SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att->image->color_format));
+            /* all images must have same sample count */
+            SOKOL_ASSERT(att->image->sample_count == img->sample_count);
+        }
+        else {
+            img_continuous = false;
+        }
+    }
+    /* check depth-stencil attachment */
+    const _sg_attachment* ds_att = &pass->ds_att;
+    if (ds_att->image) {
+        SOKOL_ASSERT(ds_att->image->slot.state == SG_RESOURCESTATE_VALID);
+        SOKOL_ASSERT(ds_att->image->slot.id == ds_att->image_id);
+        SOKOL_ASSERT(ds_att->image->render_target);
+        SOKOL_ASSERT(ds_att->image->usage == SG_USAGE_IMMUTABLE);
+        SOKOL_ASSERT(ds_att->image->width == img->width);
+        SOKOL_ASSERT(ds_att->image->height == img->height);
+        SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_att->image->depth_format));
+    }
+    #endif /* SOKOL_DEBUG */
+}
+
 static bool _sg_validate_draw(_sg_pipeline* pip, 
     _sg_buffer** vbs, int num_vbs, const _sg_buffer* ib,
     _sg_image** vs_imgs, int num_vs_imgs,
@@ -1045,11 +1094,21 @@ void sg_destroy_pass(sg_id pass_id) {
     }
 }
 
-void sg_begin_pass(sg_id pass_id, const sg_pass_action* pass_action, int width, int height) {
+void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height) {
+    SOKOL_ASSERT(_sg && pass_action);
+    SOKOL_ASSERT(pass_action->_init_guard == _SG_INIT_GUARD);
+    _sg_begin_pass(&_sg->backend, 0, pass_action, width, height);
+}
+
+void sg_begin_pass(sg_id pass_id, const sg_pass_action* pass_action) {
     SOKOL_ASSERT(_sg && pass_action);
     SOKOL_ASSERT(pass_action->_init_guard == _SG_INIT_GUARD);
-    _sg_pass* pass = _sg_lookup_pass(&_sg->pools, pass_id);  // can be 0
-    _sg_begin_pass(&_sg->backend, pass, pass_action, width, height);
+    _sg_pass* pass = _sg_lookup_pass(&_sg->pools, pass_id);
+    SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_VALID);
+    _sg_validate_begin_pass(pass, pass_action);
+    const int w = pass->color_atts[0].image->width;
+    const int h = pass->color_atts[0].image->height;
+    _sg_begin_pass(&_sg->backend, pass, pass_action, w, h);
 }
 
 void sg_apply_draw_state(const sg_draw_state* ds) {

+ 77 - 30
_sokol_gfx_gl.impl.h

@@ -656,6 +656,8 @@ typedef struct {
     uint32_t frame_index;
     GLenum cur_primitive_type;
     GLenum cur_index_type;
+    int cur_pass_width;
+    int cur_pass_height;
     _sg_pipeline* cur_pipeline;
     sg_id cur_pipeline_id; 
     _sg_state_cache cache;
@@ -676,6 +678,8 @@ static void _sg_setup_backend(_sg_backend* state) {
     state->frame_index = 1;
     state->cur_primitive_type = GL_TRIANGLES;
     state->cur_index_type = 0;
+    state->cur_pass_width = 0;
+    state->cur_pass_height = 0;
     state->cur_pipeline = 0;
     state->cur_pipeline_id = SG_INVALID_ID;
     state->valid = true;
@@ -1046,23 +1050,19 @@ static void _sg_create_shader(_sg_backend* state, _sg_shader* shd, const sg_shad
         const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs;
         _sg_shader_stage* stage = &shd->stage[stage_index];
         SOKOL_ASSERT(stage->num_uniform_blocks == 0);
-        for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) {
+        stage->num_uniform_blocks = stage_desc->num_ubs;
+        for (int ub_index = 0; ub_index < stage_desc->num_ubs; ub_index++) {
             const sg_shader_uniform_block_desc* ub_desc = &stage_desc->ub[ub_index];
-            if (ub_desc->size == 0) {
-                break;
-            }
-            _sg_uniform_block* ub = &stage->uniform_blocks[stage->num_uniform_blocks++];
+            _sg_uniform_block* ub = &stage->uniform_blocks[ub_index];
             ub->size = ub_desc->size;
             SOKOL_ASSERT(ub->num_uniforms == 0);
-            for (int u_index = 0; u_index < SG_MAX_UNIFORMS; u_index++) {
+            ub->num_uniforms = ub_desc->num_uniforms;
+            for (int u_index = 0; u_index < ub_desc->num_uniforms; u_index++) {
                 const sg_shader_uniform_desc* u_desc = &ub_desc->u[u_index];
-                if (u_desc->type == SG_UNIFORMTYPE_INVALID) {
-                    break;
-                }
-                _sg_uniform* u = &ub->uniforms[ub->num_uniforms++];
+                _sg_uniform* u = &ub->uniforms[u_index];
                 u->type = u_desc->type;
                 u->offset = u_desc->offset;
-                u->count = u_desc->count;
+                u->count = u_desc->array_count;
                 if (u_desc->name) {
                     u->gl_loc = glGetUniformLocation(gl_prog, u_desc->name);
                 }
@@ -1287,9 +1287,32 @@ static void _sg_begin_pass(_sg_backend* state, _sg_pass* pass, const sg_pass_act
     SOKOL_ASSERT(state);
     SOKOL_ASSERT(action);
     SOKOL_ASSERT(!state->in_pass);
+    _SG_GL_CHECK_ERROR();
     state->in_pass = true;
+    state->cur_pass_width = w;
+    state->cur_pass_height = h;
     if (pass) {
-
+        /* offscreen pass */
+        SOKOL_ASSERT(pass->gl_fb);
+        glBindFramebuffer(GL_FRAMEBUFFER, pass->gl_fb);
+        #if !defined(SOKOL_USE_GLES2)
+        GLenum att[SG_MAX_COLOR_ATTACHMENTS] = {
+            GL_COLOR_ATTACHMENT0,
+            GL_COLOR_ATTACHMENT1,
+            GL_COLOR_ATTACHMENT2,
+            GL_COLOR_ATTACHMENT3
+        };
+        int num_attrs = 0;
+        for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+            if (pass->color_atts[num_attrs].image) {
+                num_attrs++;
+            }
+            else {
+                break;
+            }
+        }
+        glDrawBuffers(num_attrs, att);
+        #endif
     }
     else {
         /* default pass */
@@ -1313,26 +1336,50 @@ static void _sg_begin_pass(_sg_backend* state, _sg_pass* pass, const sg_pass_act
         state->cache.ds.stencil_write_mask = 0xFF;
         glStencilMask(0xFF);
     }
-    /* FIXME: multiple-render-target! */
-    GLbitfield clear_mask = 0;
-    if (action->actions & SG_PASSACTION_CLEAR_COLOR0) {
-        clear_mask |= GL_COLOR_BUFFER_BIT;
-        const float* c = action->color[0];
-        glClearColor(c[0], c[1], c[2], c[3]);
-    }
-    if (action->actions & SG_PASSACTION_CLEAR_DEPTH_STENCIL) {
-        /* FIXME: hmm separate depth/stencil clear? */
-        clear_mask |= GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT;
-        #ifdef SOKOL_USE_GLCORE33
-        glClearDepth(action->depth);
-        #else
-        glClearDepthf(action->depth);
-        #endif
-        glClearStencil(action->stencil);
+    bool use_mrt_clear = (0 != pass);
+    #if defined(SOKOL_USE_GLES2)
+    use_mrt_clear = false;
+    #endif
+    if (!use_mrt_clear) {
+        GLbitfield clear_mask = 0;
+        if (action->actions & SG_PASSACTION_CLEAR_COLOR0) {
+            clear_mask |= GL_COLOR_BUFFER_BIT;
+            const float* c = action->color[0];
+            glClearColor(c[0], c[1], c[2], c[3]);
+        }
+        if (action->actions & SG_PASSACTION_CLEAR_DEPTH_STENCIL) {
+            /* FIXME: hmm separate depth/stencil clear? */
+            clear_mask |= GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT;
+            #ifdef SOKOL_USE_GLCORE33
+            glClearDepth(action->depth);
+            #else
+            glClearDepthf(action->depth);
+            #endif
+            glClearStencil(action->stencil);
+        }
+        if (0 != clear_mask) {
+            glClear(clear_mask);
+        }
     }
-    if (0 != clear_mask) {
-        glClear(clear_mask);
+    #if !defined SOKOL_USE_GLES2
+    else {
+        SOKOL_ASSERT(pass);
+        for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
+            if (pass->color_atts[i].image) {
+                if (action->actions & (SG_PASSACTION_CLEAR_COLOR0<<i)) {
+                    glClearBufferfv(GL_COLOR, i, action->color[i]);
+                }
+            }
+            else {
+                break;
+            }
+        }
+        if (pass->ds_att.image && (action->actions & SG_PASSACTION_CLEAR_DEPTH_STENCIL)) {
+            glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth, action->stencil);
+        }
     }
+    #endif
+    _SG_GL_CHECK_ERROR();
 }
 
 static void _sg_end_pass(_sg_backend* state) {

+ 10 - 5
sokol_gfx.h

@@ -416,11 +416,12 @@ typedef struct {
     const char* name;
     int offset;
     sg_uniform_type type;   /* SG_UNIFORMTYPE_INVALID if not used */
-    int count; 
+    int array_count; 
 } sg_shader_uniform_desc;
 
 typedef struct {
     int size;
+    int num_uniforms;
     sg_shader_uniform_desc u[SG_MAX_UNIFORMS];
 } sg_shader_uniform_block_desc;
 
@@ -433,9 +434,11 @@ typedef struct {
     /* source code (only used in GL backends) */
     const char* source;
     /* uniform block descriptions */
+    int num_ubs;
     sg_shader_uniform_block_desc ub[SG_MAX_SHADERSTAGE_UBS];
     /* image descriptions */
-    sg_shader_image_desc images[SG_MAX_SHADERSTAGE_IMAGES];
+    int num_images;
+    sg_shader_image_desc image[SG_MAX_SHADERSTAGE_IMAGES];
 } sg_shader_stage_desc;
 
 typedef struct {
@@ -501,8 +504,9 @@ extern void sg_init_desc(sg_desc* desc);
 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);
-extern void sg_init_uniform_block(sg_shader_uniform_block_desc* desc, int ub_size); 
-extern void sg_init_named_uniform(sg_shader_uniform_desc* desc, const char* name, int ub_offset, sg_uniform_type type, int array_count);
+extern void sg_init_uniform_block(sg_shader_desc* desc, sg_shader_stage stage, int ub_size); 
+extern void sg_init_named_uniform(sg_shader_desc* desc, sg_shader_stage stage, const char* name, int ub_offset, sg_uniform_type type, int array_count);
+extern void sg_init_named_image(sg_shader_desc* desc, sg_shader_stage stage, const char* name, sg_image_type type);
 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);
@@ -532,7 +536,8 @@ extern void sg_update_buffer(sg_id buf, const void* data_ptr, int data_size);
 extern void sg_update_image(sg_id img, int num_data_items, const void** data_ptrs, int* data_sizes); 
 
 /* rendering */
-extern void sg_begin_pass(sg_id pass, const sg_pass_action* pass_action, int width, int height);
+extern void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height);
+extern void sg_begin_pass(sg_id pass, const sg_pass_action* pass_action);
 extern void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left);
 extern void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left);
 extern void sg_apply_draw_state(const sg_draw_state* ds);