|
@@ -3418,6 +3418,7 @@ typedef struct sg_frame_stats {
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_NO_RT, "pass depth attachment image must be have render_target=true") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES, "pass depth attachment image size must match color attachment image size") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT, "pass depth attachment sample count must match color attachment sample count") \
|
|
|
+ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_CANARY, "sg_begin_pass: pass struct not initialized") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS, "sg_begin_pass: attachments object no longer alive") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_VALID, "sg_begin_pass: attachemnts object not in resource state VALID") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE, "sg_begin_pass: one or more color attachment images are not valid") \
|
|
@@ -3452,6 +3453,8 @@ typedef struct sg_frame_stats {
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID, "sg_apply_pipeline: pipeline object not in valid state") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_EXISTS, "sg_apply_pipeline: shader object no longer alive") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_VALID, "sg_apply_pipeline: shader object not in valid state") \
|
|
|
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS, "sg_apply_pipeline: current pass attachments no longer alive") \
|
|
|
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID, "sg_apply_pipeline: current pass attachments not in valid state") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_ATT_COUNT, "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_COLOR_FORMAT, "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format") \
|
|
|
_SG_LOGITEM_XMACRO(VALIDATE_APIP_DEPTH_FORMAT, "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format") \
|
|
@@ -4939,7 +4942,7 @@ typedef struct {
|
|
|
|
|
|
typedef struct {
|
|
|
_sg_slot_t slot;
|
|
|
- _sg_pass_common_t cmn;
|
|
|
+ _sg_attachemnts_common_t cmn;
|
|
|
struct {
|
|
|
_sg_dummy_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS];
|
|
|
_sg_dummy_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS];
|
|
@@ -5356,10 +5359,6 @@ typedef struct {
|
|
|
int ub_size;
|
|
|
int cur_ub_offset;
|
|
|
uint8_t* cur_ub_base_ptr;
|
|
|
- bool in_pass;
|
|
|
- bool pass_valid;
|
|
|
- int cur_width;
|
|
|
- int cur_height;
|
|
|
_sg_mtl_state_cache_t state_cache;
|
|
|
_sg_mtl_idpool_t idpool;
|
|
|
dispatch_semaphore_t sem;
|
|
@@ -5580,10 +5579,21 @@ typedef struct {
|
|
|
bool valid;
|
|
|
sg_desc desc; // original desc with default values patched in
|
|
|
uint32_t frame_index;
|
|
|
- sg_attachments cur_atts;
|
|
|
+ struct {
|
|
|
+ bool valid;
|
|
|
+ bool in_pass;
|
|
|
+ sg_attachments atts_id; // SG_INVALID_ID in a swapchain pass
|
|
|
+ _sg_attachments_t* atts; // 0 in a swapchain pass
|
|
|
+ int width;
|
|
|
+ int height;
|
|
|
+ struct {
|
|
|
+ sg_pixel_format color_fmt;
|
|
|
+ sg_pixel_format depth_fmt;
|
|
|
+ int sample_count;
|
|
|
+ } swapchain;
|
|
|
+ } cur_pass;
|
|
|
sg_pipeline cur_pipeline;
|
|
|
- bool pass_valid;
|
|
|
- bool bindings_applied;
|
|
|
+ bool apply_bindings_called;
|
|
|
bool next_draw_valid;
|
|
|
#if defined(SOKOL_DEBUG)
|
|
|
sg_log_item validate_error;
|
|
@@ -12253,21 +12263,9 @@ _SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_ds_image(const _sg_attachments_t
|
|
|
_SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass_action* action, _sg_attachments_t* atts, const sg_swapchain* swapchain) {
|
|
|
SOKOL_ASSERT(action);
|
|
|
SOKOL_ASSERT(swapchain);
|
|
|
- SOKOL_ASSERT(!_sg.mtl.in_pass);
|
|
|
SOKOL_ASSERT(_sg.mtl.cmd_queue);
|
|
|
SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder);
|
|
|
SOKOL_ASSERT(nil == _sg.mtl.cur_drawable);
|
|
|
- _sg.mtl.in_pass = true;
|
|
|
- // FIXME: move this up into sg_begin_pass
|
|
|
- if (atts) {
|
|
|
- _sg.mtl.cur_width = atts->cmn.width;
|
|
|
- _sg.mtl.cur_height = atts->cmn.height;
|
|
|
- } else {
|
|
|
- SOKOL_ASSERT(swapchain->width > 0);
|
|
|
- SOKOL_ASSERT(swapchain->height > 0);
|
|
|
- _sg.mtl.cur_width = swapchain->width;
|
|
|
- _sg.mtl.cur_height = swapchain->height;
|
|
|
- }
|
|
|
_sg_mtl_clear_state_cache();
|
|
|
|
|
|
/*
|
|
@@ -12304,9 +12302,12 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass_action* action, _sg_attachm
|
|
|
// offscreen render pass
|
|
|
pass_desc = [MTLRenderPassDescriptor renderPassDescriptor];
|
|
|
} else {
|
|
|
- // a swapchain pass descriptor will not be valid if window is minimized, don't do any rendering in this case
|
|
|
+ // NOTE: at least in macOS Sonoma this no longer seems to be the case, the
|
|
|
+ // render pass descriptor is also valid in a minimized window
|
|
|
+ // ===
|
|
|
+ // an MTKView render pass descriptor will not be valid if window is minimized, don't do any rendering in this case
|
|
|
if (0 == swapchain->metal.render_pass_descriptor) {
|
|
|
- _sg.mtl.pass_valid = false;
|
|
|
+ _sg.cur_pass.valid = false;
|
|
|
return;
|
|
|
}
|
|
|
pass_desc = (__bridge MTLRenderPassDescriptor*) swapchain->metal.render_pass_descriptor;
|
|
@@ -12318,7 +12319,6 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass_action* action, _sg_attachm
|
|
|
_sg.mtl.cur_drawable = (__bridge id<MTLDrawable>) swapchain->metal.drawable;
|
|
|
}
|
|
|
SOKOL_ASSERT(pass_desc);
|
|
|
- _sg.mtl.pass_valid = true;
|
|
|
if (atts) {
|
|
|
// setup pass descriptor for offscreen rendering
|
|
|
SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_VALID);
|
|
@@ -12414,10 +12414,13 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass_action* action, _sg_attachm
|
|
|
pass_desc.stencilAttachment.clearStencil = action->stencil.clear_value;
|
|
|
}
|
|
|
|
|
|
+ // NOTE: at least in macOS Sonoma, the following is no longer the case, a valid
|
|
|
+ // render command encoder is also returned in a minimized window
|
|
|
+ // ===
|
|
|
// create a render command encoder, this might return nil if window is minimized
|
|
|
_sg.mtl.cmd_encoder = [_sg.mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc];
|
|
|
if (nil == _sg.mtl.cmd_encoder) {
|
|
|
- _sg.mtl.pass_valid = false;
|
|
|
+ _sg.cur_pass.valid = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -12426,9 +12429,6 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass_action* action, _sg_attachm
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_end_pass(void) {
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- _sg.mtl.in_pass = false;
|
|
|
- _sg.mtl.pass_valid = false;
|
|
|
if (nil != _sg.mtl.cmd_encoder) {
|
|
|
[_sg.mtl.cmd_encoder endEncoding];
|
|
|
// NOTE: MTLRenderCommandEncoder is autoreleased
|
|
@@ -12442,8 +12442,6 @@ _SOKOL_PRIVATE void _sg_mtl_end_pass(void) {
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_commit(void) {
|
|
|
- SOKOL_ASSERT(!_sg.mtl.in_pass);
|
|
|
- SOKOL_ASSERT(!_sg.mtl.pass_valid);
|
|
|
SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder);
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer);
|
|
|
|
|
@@ -12464,14 +12462,11 @@ _SOKOL_PRIVATE void _sg_mtl_commit(void) {
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) {
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.height > 0);
|
|
|
MTLViewport vp;
|
|
|
vp.originX = (double) x;
|
|
|
- vp.originY = (double) (origin_top_left ? y : (_sg.mtl.cur_height - (y + h)));
|
|
|
+ vp.originY = (double) (origin_top_left ? y : (_sg.cur_pass.height - (y + h)));
|
|
|
vp.width = (double) w;
|
|
|
vp.height = (double) h;
|
|
|
vp.znear = 0.0;
|
|
@@ -12480,16 +12475,14 @@ _SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool orig
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) {
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.width > 0);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.height > 0);
|
|
|
// clip against framebuffer rect
|
|
|
- const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.mtl.cur_width, _sg.mtl.cur_height);
|
|
|
+ const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height);
|
|
|
MTLScissorRect r;
|
|
|
r.x = (NSUInteger)clip.x;
|
|
|
- r.y = (NSUInteger) (origin_top_left ? clip.y : (_sg.mtl.cur_height - (clip.y + clip.h)));
|
|
|
+ r.y = (NSUInteger) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h)));
|
|
|
r.width = (NSUInteger)clip.w;
|
|
|
r.height = (NSUInteger)clip.h;
|
|
|
[_sg.mtl.cmd_encoder setScissorRect:r];
|
|
@@ -12498,10 +12491,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool
|
|
|
_SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) {
|
|
|
SOKOL_ASSERT(pip);
|
|
|
SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id));
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
|
|
|
if (_sg.mtl.state_cache.cur_pipeline_id.id != pip->slot.id) {
|
|
@@ -12530,10 +12519,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) {
|
|
|
_SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) {
|
|
|
SOKOL_ASSERT(bnd);
|
|
|
SOKOL_ASSERT(bnd->pip);
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return false;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
|
|
|
// store index buffer binding, this will be needed later in sg_draw()
|
|
@@ -12616,10 +12601,6 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) {
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) {
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size);
|
|
|
SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0);
|
|
@@ -12643,10 +12624,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_i
|
|
|
}
|
|
|
|
|
|
_SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) {
|
|
|
- SOKOL_ASSERT(_sg.mtl.in_pass);
|
|
|
- if (!_sg.mtl.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder);
|
|
|
SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && (_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id));
|
|
|
if (SG_INDEXTYPE_NONE != _sg.mtl.state_cache.cur_pipeline->cmn.index_type) {
|
|
@@ -15935,6 +15912,8 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) {
|
|
|
return true;
|
|
|
}
|
|
|
_sg_validate_begin();
|
|
|
+ _SG_VALIDATE(pass->_start_canary == 0, VALIDATE_BEGINPASS_CANARY);
|
|
|
+ _SG_VALIDATE(pass->_end_canary == 0, VALIDATE_BEGINPASS_CANARY);
|
|
|
if (pass->attachments.id == SG_INVALID_ID) {
|
|
|
// this is a swapchain pass
|
|
|
_SG_VALIDATE(pass->swapchain.width > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH);
|
|
@@ -15962,27 +15941,30 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) {
|
|
|
} else {
|
|
|
// this is an 'offscreen pass'
|
|
|
const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, pass->attachments.id);
|
|
|
- _SG_VALIDATE(atts != 0, VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS);
|
|
|
- _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_ATTACHMENTS_VALID);
|
|
|
- for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
|
|
|
- const _sg_attachment_common_t* color_att = &atts->cmn.colors[i];
|
|
|
- const _sg_image_t* color_img = _sg_attachments_color_image(atts, i);
|
|
|
- if (color_img) {
|
|
|
- _SG_VALIDATE(color_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE);
|
|
|
- _SG_VALIDATE(color_img->slot.id == color_att->image_id.id, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE);
|
|
|
+ if (atts) {
|
|
|
+ _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_ATTACHMENTS_VALID);
|
|
|
+ for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
|
|
|
+ const _sg_attachment_common_t* color_att = &atts->cmn.colors[i];
|
|
|
+ const _sg_image_t* color_img = _sg_attachments_color_image(atts, i);
|
|
|
+ if (color_img) {
|
|
|
+ _SG_VALIDATE(color_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE);
|
|
|
+ _SG_VALIDATE(color_img->slot.id == color_att->image_id.id, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE);
|
|
|
+ }
|
|
|
+ const _sg_attachment_common_t* resolve_att = &atts->cmn.resolves[i];
|
|
|
+ const _sg_image_t* resolve_img = _sg_attachments_resolve_image(atts, i);
|
|
|
+ if (resolve_img) {
|
|
|
+ _SG_VALIDATE(resolve_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE);
|
|
|
+ _SG_VALIDATE(resolve_img->slot.id == resolve_att->image_id.id, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE);
|
|
|
+ }
|
|
|
}
|
|
|
- const _sg_attachment_common_t* resolve_att = &atts->cmn.resolves[i];
|
|
|
- const _sg_image_t* resolve_img = _sg_attachments_resolve_image(atts, i);
|
|
|
- if (resolve_img) {
|
|
|
- _SG_VALIDATE(resolve_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE);
|
|
|
- _SG_VALIDATE(resolve_img->slot.id == resolve_att->image_id.id, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE);
|
|
|
+ const _sg_image_t* ds_img = _sg_attachments_ds_image(atts);
|
|
|
+ if (ds_img) {
|
|
|
+ const _sg_attachment_common_t* att = &atts->cmn.depth_stencil;
|
|
|
+ _SG_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE);
|
|
|
+ _SG_VALIDATE(ds_img->slot.id == att->image_id.id, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE);
|
|
|
}
|
|
|
- }
|
|
|
- const _sg_image_t* ds_img = _sg_attachments_ds_image(atts);
|
|
|
- if (ds_img) {
|
|
|
- const _sg_attachment_common_t* att = &atts->cmn.depth_stencil;
|
|
|
- _SG_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE);
|
|
|
- _SG_VALIDATE(ds_img->slot.id == att->image_id.id, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE);
|
|
|
+ } else {
|
|
|
+ _SG_VALIDATE(atts != 0, VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS);
|
|
|
}
|
|
|
// swapchain params must be all zero!
|
|
|
_SG_VALIDATE(pass->swapchain.width == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH_NOTSET);
|
|
@@ -16031,9 +16013,13 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) {
|
|
|
_SG_VALIDATE(pip->shader->slot.id == pip->cmn.shader_id.id, VALIDATE_APIP_SHADER_EXISTS);
|
|
|
_SG_VALIDATE(pip->shader->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_SHADER_VALID);
|
|
|
// check that pipeline attributes match current pass attributes
|
|
|
- const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, _sg.cur_atts.id);
|
|
|
- if (atts) {
|
|
|
+ if (_sg.cur_pass.atts_id.id != SG_INVALID_ID) {
|
|
|
// an offscreen pass
|
|
|
+ const _sg_attachments_t* atts = _sg.cur_pass.atts;
|
|
|
+ SOKOL_ASSERT(atts);
|
|
|
+ _SG_VALIDATE(atts->slot.id == _sg.cur_pass.atts_id.id, VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS);
|
|
|
+ _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID);
|
|
|
+
|
|
|
_SG_VALIDATE(pip->cmn.color_count == atts->cmn.num_colors, VALIDATE_APIP_ATT_COUNT);
|
|
|
for (int i = 0; i < pip->cmn.color_count; i++) {
|
|
|
const _sg_image_t* att_img = _sg_attachments_color_image(atts, i);
|
|
@@ -16048,11 +16034,10 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) {
|
|
|
}
|
|
|
} else {
|
|
|
// default pass
|
|
|
- // FIXME: match against swapchain attributes
|
|
|
_SG_VALIDATE(pip->cmn.color_count == 1, VALIDATE_APIP_ATT_COUNT);
|
|
|
- _SG_VALIDATE(pip->cmn.colors[0].pixel_format == _sg.desc.context.color_format, VALIDATE_APIP_COLOR_FORMAT);
|
|
|
- _SG_VALIDATE(pip->cmn.depth.pixel_format == _sg.desc.context.depth_format, VALIDATE_APIP_DEPTH_FORMAT);
|
|
|
- _SG_VALIDATE(pip->cmn.sample_count == _sg.desc.context.sample_count, VALIDATE_APIP_SAMPLE_COUNT);
|
|
|
+ _SG_VALIDATE(pip->cmn.colors[0].pixel_format == _sg.cur_pass.swapchain.color_fmt, VALIDATE_APIP_COLOR_FORMAT);
|
|
|
+ _SG_VALIDATE(pip->cmn.depth.pixel_format == _sg.cur_pass.swapchain.depth_fmt, VALIDATE_APIP_DEPTH_FORMAT);
|
|
|
+ _SG_VALIDATE(pip->cmn.sample_count == _sg.cur_pass.swapchain.sample_count, VALIDATE_APIP_SAMPLE_COUNT);
|
|
|
}
|
|
|
return _sg_validate_end();
|
|
|
#endif
|
|
@@ -17580,33 +17565,49 @@ SOKOL_API_IMPL void sg_destroy_attachments(sg_attachments atts_id) {
|
|
|
|
|
|
SOKOL_API_IMPL void sg_begin_pass(const sg_pass* pass) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(!_sg.cur_pass.valid);
|
|
|
+ SOKOL_ASSERT(!_sg.cur_pass.in_pass);
|
|
|
SOKOL_ASSERT(pass);
|
|
|
SOKOL_ASSERT((pass->_start_canary == 0) && (pass->_end_canary == 0));
|
|
|
- _sg.pass_valid = false;
|
|
|
- _sg.cur_atts.id = SG_INVALID_ID;
|
|
|
if (!_sg_validate_begin_pass(pass)) {
|
|
|
return;
|
|
|
}
|
|
|
- _sg_attachments_t* atts = 0;
|
|
|
if (pass->attachments.id != SG_INVALID_ID) {
|
|
|
- atts = _sg_lookup_attachments(&_sg.pools, pass->attachments.id);
|
|
|
- if (0 == atts) {
|
|
|
+ // an offscreen pass
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.atts == 0);
|
|
|
+ _sg.cur_pass.atts = _sg_lookup_attachments(&_sg.pools, pass->attachments.id);
|
|
|
+ if (0 == _sg.cur_pass.atts) {
|
|
|
_SG_ERROR(BEGINPASS_ATTACHMENT_INVALID);
|
|
|
return;
|
|
|
}
|
|
|
- _sg.cur_atts = pass->attachments;
|
|
|
- }
|
|
|
+ _sg.cur_pass.atts_id = pass->attachments;
|
|
|
+ _sg.cur_pass.width = _sg.cur_pass.atts->cmn.width;
|
|
|
+ _sg.cur_pass.height = _sg.cur_pass.atts->cmn.height;
|
|
|
+ } else {
|
|
|
+ // a swapchain pass
|
|
|
+ SOKOL_ASSERT(pass->swapchain.width > 0);
|
|
|
+ SOKOL_ASSERT(pass->swapchain.height > 0);
|
|
|
+ SOKOL_ASSERT(pass->swapchain.color_format > SG_PIXELFORMAT_NONE);
|
|
|
+ SOKOL_ASSERT(pass->swapchain.sample_count > 0);
|
|
|
+ _sg.cur_pass.width = pass->swapchain.width;
|
|
|
+ _sg.cur_pass.height = pass->swapchain.height;
|
|
|
+ _sg.cur_pass.swapchain.color_fmt = pass->swapchain.color_format;
|
|
|
+ _sg.cur_pass.swapchain.depth_fmt = pass->swapchain.depth_format;
|
|
|
+ _sg.cur_pass.swapchain.sample_count = pass->swapchain.sample_count;
|
|
|
+ }
|
|
|
+ _sg.cur_pass.valid = true; // may be overruled by backend begin-pass functions
|
|
|
+ _sg.cur_pass.in_pass = true;
|
|
|
sg_pass_action pa;
|
|
|
_sg_resolve_pass_action(&pass->action, &pa);
|
|
|
- _sg.pass_valid = true;
|
|
|
- _sg_begin_pass(&pa, atts, &pass->swapchain);
|
|
|
+ _sg_begin_pass(&pa, _sg.cur_pass.atts, &pass->swapchain);
|
|
|
_SG_TRACE_ARGS(begin_pass, pass);
|
|
|
}
|
|
|
|
|
|
SOKOL_API_IMPL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
_sg_stats_add(num_apply_viewport, 1);
|
|
|
- if (!_sg.pass_valid) {
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
return;
|
|
|
}
|
|
|
_sg_apply_viewport(x, y, width, height, origin_top_left);
|
|
@@ -17619,8 +17620,9 @@ SOKOL_API_IMPL void sg_apply_viewportf(float x, float y, float width, float heig
|
|
|
|
|
|
SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
_sg_stats_add(num_apply_scissor_rect, 1);
|
|
|
- if (!_sg.pass_valid) {
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
return;
|
|
|
}
|
|
|
_sg_apply_scissor_rect(x, y, width, height, origin_top_left);
|
|
@@ -17633,13 +17635,14 @@ SOKOL_API_IMPL void sg_apply_scissor_rectf(float x, float y, float width, float
|
|
|
|
|
|
SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
_sg_stats_add(num_apply_pipeline, 1);
|
|
|
- _sg.bindings_applied = false;
|
|
|
+ _sg.apply_bindings_called = false;
|
|
|
if (!_sg_validate_apply_pipeline(pip_id)) {
|
|
|
_sg.next_draw_valid = false;
|
|
|
return;
|
|
|
}
|
|
|
- if (!_sg.pass_valid) {
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
return;
|
|
|
}
|
|
|
_sg.cur_pipeline = pip_id;
|
|
@@ -17653,14 +17656,18 @@ SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) {
|
|
|
|
|
|
SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
SOKOL_ASSERT(bindings);
|
|
|
SOKOL_ASSERT((bindings->_start_canary == 0) && (bindings->_end_canary==0));
|
|
|
_sg_stats_add(num_apply_bindings, 1);
|
|
|
+ _sg.apply_bindings_called = true;
|
|
|
if (!_sg_validate_apply_bindings(bindings)) {
|
|
|
_sg.next_draw_valid = false;
|
|
|
return;
|
|
|
}
|
|
|
- _sg.bindings_applied = true;
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
_sg_bindings_t bnd;
|
|
|
_sg_clear(&bnd, sizeof(bnd));
|
|
@@ -17755,6 +17762,7 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) {
|
|
|
|
|
|
SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS));
|
|
|
SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS));
|
|
|
SOKOL_ASSERT(data && data->ptr && (data->size > 0));
|
|
@@ -17764,7 +17772,7 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const
|
|
|
_sg.next_draw_valid = false;
|
|
|
return;
|
|
|
}
|
|
|
- if (!_sg.pass_valid) {
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
return;
|
|
|
}
|
|
|
if (!_sg.next_draw_valid) {
|
|
@@ -17776,22 +17784,23 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const
|
|
|
|
|
|
SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instances) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
SOKOL_ASSERT(base_element >= 0);
|
|
|
SOKOL_ASSERT(num_elements >= 0);
|
|
|
SOKOL_ASSERT(num_instances >= 0);
|
|
|
_sg_stats_add(num_draw, 1);
|
|
|
#if defined(SOKOL_DEBUG)
|
|
|
- if (!_sg.bindings_applied) {
|
|
|
+ if (!_sg.apply_bindings_called) {
|
|
|
_SG_WARN(DRAW_WITHOUT_BINDINGS);
|
|
|
}
|
|
|
#endif
|
|
|
- if (!_sg.pass_valid) {
|
|
|
+ if (!_sg.cur_pass.valid) {
|
|
|
return;
|
|
|
}
|
|
|
if (!_sg.next_draw_valid) {
|
|
|
return;
|
|
|
}
|
|
|
- if (!_sg.bindings_applied) {
|
|
|
+ if (!_sg.apply_bindings_called) {
|
|
|
return;
|
|
|
}
|
|
|
/* attempting to draw with zero elements or instances is not technically an
|
|
@@ -17806,19 +17815,19 @@ SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instance
|
|
|
|
|
|
SOKOL_API_IMPL void sg_end_pass(void) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(_sg.cur_pass.in_pass);
|
|
|
_sg_stats_add(num_passes, 1);
|
|
|
- if (!_sg.pass_valid) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ // NOTE: don't exit early if !_sg.cur_pass.valid
|
|
|
_sg_end_pass();
|
|
|
- _sg.cur_atts.id = SG_INVALID_ID;
|
|
|
_sg.cur_pipeline.id = SG_INVALID_ID;
|
|
|
- _sg.pass_valid = false;
|
|
|
+ _sg_clear(&_sg.cur_pass, sizeof(_sg.cur_pass));
|
|
|
_SG_TRACE_NOARGS(end_pass);
|
|
|
}
|
|
|
|
|
|
SOKOL_API_IMPL void sg_commit(void) {
|
|
|
SOKOL_ASSERT(_sg.valid);
|
|
|
+ SOKOL_ASSERT(!_sg.cur_pass.valid);
|
|
|
+ SOKOL_ASSERT(!_sg.cur_pass.in_pass);
|
|
|
_sg_commit();
|
|
|
_sg.stats.frame_index = _sg.frame_index;
|
|
|
_sg.prev_stats = _sg.stats;
|