31 MTLRenderPassAttachmentDescriptor* attachment) {
37 VALIDATION_LOG <<
"Resolve store action specified on attachment but no "
38 "resolve texture was specified.";
43 VALIDATION_LOG <<
"A resolve texture was specified even though the store "
44 "action doesn't require it.";
52 attachment.resolveTexture =
59 MTLRenderPassAttachmentDescriptor* attachment) {
77 MTLRenderPassColorAttachmentDescriptor* attachment) {
87 MTLRenderPassDepthAttachmentDescriptor* attachment) {
97 MTLRenderPassStencilAttachmentDescriptor* attachment) {
107 auto result = [MTLRenderPassDescriptor renderPassDescriptor];
112 result.colorAttachments[index]);
115 if (!configured_attachment) {
122 if (depth.has_value() &&
130 if (stencil.has_value() &&
139RenderPassMTL::RenderPassMTL(std::shared_ptr<const Context> context,
140 const RenderTarget&
target,
141 id<MTLCommandBuffer> buffer)
142 : RenderPass(
std::move(context),
target),
145 if (!buffer_ || !
desc_ || !render_target_.IsValid()) {
148 encoder_ = [buffer_ renderCommandEncoderWithDescriptor:
desc_];
154 is_metal_trace_active_ =
155 [[MTLCaptureManager sharedCaptureManager] isCapturing];
157 pass_bindings_.SetEncoder(encoder_);
158 pass_bindings_.SetViewport(
164RenderPassMTL::~RenderPassMTL() {
165 if (!did_finish_encoding_) {
166 [encoder_ endEncoding];
167 did_finish_encoding_ =
true;
171bool RenderPassMTL::IsValid()
const {
175void RenderPassMTL::OnSetLabel(std::string_view label) {
180 encoder_.label = @(std::string(label).c_str());
184bool RenderPassMTL::OnEncodeCommands(
const Context& context)
const {
185 did_finish_encoding_ =
true;
186 [encoder_ endEncoding];
194 if (!
view.GetBuffer()) {
199 if (!device_buffer) {
203 auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
209 return pass.
SetBuffer(stage, bind_index,
view.GetRange().offset, buffer);
217 if (!sampler || !
texture.IsValid()) {
221 if (
texture.NeedsMipmapGeneration()) {
225 <<
"Texture at binding index " << bind_index
226 <<
" has a mip count > 1, but the mipmap has not been generated.";
232 TextureMTL::Cast(
texture).GetMTLTexture()) &&
234 SamplerMTL::Cast(*sampler).GetMTLSamplerState());
238void RenderPassMTL::SetPipeline(PipelineRef pipeline) {
239 const PipelineDescriptor& pipeline_desc = pipeline->GetDescriptor();
240 context_->GetPipelineLibrary()->LogPipelineUsage(pipeline_desc);
241 primitive_type_ = pipeline_desc.GetPrimitiveType();
242 pass_bindings_.SetRenderPipelineState(
243 PipelineMTL::Cast(*pipeline).GetMTLRenderPipelineState());
244 pass_bindings_.SetDepthStencilState(
245 PipelineMTL::Cast(*pipeline).GetMTLDepthStencilState());
247 [encoder_ setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
248 WindingOrder::kClockwise
249 ? MTLWindingClockwise
250 : MTLWindingCounterClockwise];
251 [encoder_ setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())];
252 [encoder_ setTriangleFillMode:ToMTLTriangleFillMode(
253 pipeline_desc.GetPolygonMode())];
254 has_valid_pipeline_ =
true;
258void RenderPassMTL::SetCommandLabel(std::string_view label) {
260 if (is_metal_trace_active_) {
262 std::string label_copy(label);
263 [encoder_ pushDebugGroup:@(label_copy.c_str())];
269void RenderPassMTL::SetStencilReference(uint32_t value) {
270 pass_bindings_.SetStencilRef(value);
274void RenderPassMTL::SetBaseVertex(uint64_t value) {
275 base_vertex_ =
value;
279void RenderPassMTL::SetViewport(Viewport viewport) {
280 pass_bindings_.SetViewport(viewport);
284void RenderPassMTL::SetScissor(IRect32 scissor) {
285 pass_bindings_.SetScissor(scissor);
289void RenderPassMTL::SetElementCount(
size_t count) {
290 vertex_count_ = count;
294void RenderPassMTL::SetInstanceCount(
size_t count) {
295 instance_count_ = count;
299bool RenderPassMTL::SetVertexBuffer(BufferView vertex_buffers[],
300 size_t vertex_buffer_count) {
301 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
305 for (
size_t i = 0;
i < vertex_buffer_count;
i++) {
306 if (!
Bind(pass_bindings_, ShaderStage::kVertex,
307 VertexDescriptor::kReservedVertexBufferIndex -
i,
308 vertex_buffers[
i])) {
317bool RenderPassMTL::SetIndexBuffer(BufferView index_buffer,
318 IndexType index_type) {
319 if (!ValidateIndexBuffer(index_buffer, index_type)) {
323 if (index_type != IndexType::kNone) {
325 index_buffer_ = std::move(index_buffer);
333 if (!has_valid_pipeline_) {
337 if (!index_buffer_) {
338 if (instance_count_ != 1u) {
340 vertexStart:base_vertex_
341 vertexCount:vertex_count_
342 instanceCount:instance_count_
346 vertexStart:base_vertex_
347 vertexCount:vertex_count_];
350 id<MTLBuffer> mtl_index_buffer =
351 DeviceBufferMTL::Cast(*index_buffer_.GetBuffer()).GetMTLBuffer();
352 if (instance_count_ != 1u) {
354 indexCount:vertex_count_
355 indexType:index_type_
356 indexBuffer:mtl_index_buffer
357 indexBufferOffset:index_buffer_.GetRange().offset
358 instanceCount:instance_count_
359 baseVertex:base_vertex_
363 indexCount:vertex_count_
364 indexType:index_type_
365 indexBuffer:mtl_index_buffer
366 indexBufferOffset:index_buffer_.GetRange().offset];
372 [encoder_ popDebugGroup];
378 instance_count_ = 1u;
380 has_valid_pipeline_ =
false;
387bool RenderPassMTL::BindResource(ShaderStage stage,
389 const ShaderUniformSlot& slot,
390 const ShaderMetadata* metadata,
392 return Bind(pass_bindings_, stage, slot.ext_res_0,
view);
396bool RenderPassMTL::BindDynamicResource(
399 const ShaderUniformSlot& slot,
400 std::unique_ptr<ShaderMetadata> metadata,
402 return Bind(pass_bindings_, stage, slot.ext_res_0,
view);
406bool RenderPassMTL::BindResource(ShaderStage stage,
408 const SampledImageSlot& slot,
409 const ShaderMetadata* metadata,
410 std::shared_ptr<const Texture>
texture,
411 raw_ptr<const Sampler> sampler) {
415 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *
texture);
418bool RenderPassMTL::BindDynamicResource(
421 const SampledImageSlot& slot,
422 std::unique_ptr<ShaderMetadata> metadata,
423 std::shared_ptr<const Texture>
texture,
424 raw_ptr<const Sampler> sampler) {
428 return Bind(pass_bindings_, stage, slot.texture_index, sampler, *
texture);
static TextureMTL & Cast(Texture &base)
bool IterateAllColorAttachments(const std::function< bool(size_t index, const ColorAttachment &attachment)> &iterator) const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
id< MTLTexture > GetMTLTexture() const
A wrapper around a raw ptr that adds additional unopt mode only checks.
std::optional< PipelineDescriptor > desc_
static bool ConfigureColorAttachment(const ColorAttachment &desc, MTLRenderPassColorAttachmentDescriptor *attachment)
static bool ConfigureDepthAttachment(const DepthAttachment &desc, MTLRenderPassDepthAttachmentDescriptor *attachment)
constexpr MTLLoadAction ToMTLLoadAction(LoadAction action)
@ kStoreAndMultisampleResolve
static MTLRenderPassDescriptor * ToMTLRenderPassDescriptor(const RenderTarget &desc)
static bool ConfigureResolveTextureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type)
static bool ConfigureStencilAttachment(const StencilAttachment &desc, MTLRenderPassStencilAttachmentDescriptor *attachment)
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const BufferView &view)
constexpr MTLIndexType ToMTLIndexType(IndexType type)
constexpr MTLStoreAction ToMTLStoreAction(StoreAction action)
MTLClearColor ToMTLClearColor(const Color &color)
static bool ConfigureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
std::shared_ptr< Texture > resolve_texture
std::shared_ptr< Texture > texture
Ensures that bindings on the pass are not redundantly set or updated. Avoids making the driver do add...
bool SetSampler(ShaderStage stage, uint64_t index, id< MTLSamplerState > sampler)
Set the sampler for the given stage and binding.
bool SetBuffer(ShaderStage stage, uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
Set the buffer for the given shader stage, binding, and offset.
bool SetTexture(ShaderStage stage, uint64_t index, id< MTLTexture > texture)
Set the texture for the given stage and binding.
static constexpr TRect MakeSize(const TSize< U > &size)