diff --git a/drape/metal/metal_base_context.hpp b/drape/metal/metal_base_context.hpp index fd9055c543..7354a2ecb4 100644 --- a/drape/metal/metal_base_context.hpp +++ b/drape/metal/metal_base_context.hpp @@ -3,6 +3,7 @@ #include "drape/graphics_context.hpp" #include "drape/gpu_program.hpp" +#include "drape/metal/metal_cleaner.hpp" #include "drape/metal/metal_states.hpp" #include "drape/metal/metal_texture.hpp" #include "drape/pointers.hpp" @@ -55,6 +56,10 @@ public: id GetSamplerState(TextureFilter filter, TextureWrapping wrapSMode, TextureWrapping wrapTMode); + void SetSystemPrograms(drape_ptr && programClearColor, + drape_ptr && programClearDepth, + drape_ptr && programClearColorAndDepth); + protected: void RecreateDepthTexture(m2::PointU const & screenSize); void RequestFrameDrawable(); @@ -74,6 +79,8 @@ protected: id m_frameDrawable; id m_frameCommandBuffer; id m_currentCommandEncoder; + + MetalCleaner m_cleaner; }; } // namespace metal } // namespace dp diff --git a/drape/metal/metal_base_context.mm b/drape/metal/metal_base_context.mm index c36261569b..0f19cb706f 100644 --- a/drape/metal/metal_base_context.mm +++ b/drape/metal/metal_base_context.mm @@ -1,5 +1,4 @@ #include "drape/metal/metal_base_context.hpp" -#include "drape/metal/metal_gpu_program.hpp" #include "drape/metal/metal_texture.hpp" #include "drape/framebuffer.hpp" @@ -171,6 +170,7 @@ void MetalBaseContext::ApplyFramebuffer(std::string const & framebufferLabel) void MetalBaseContext::SetClearColor(dp::Color const & color) { + m_cleaner.SetClearColor(color); m_renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(color.GetRedF(), color.GetGreenF(), color.GetBlueF(), color.GetAlphaF()); } @@ -179,8 +179,15 @@ void MetalBaseContext::Clear(uint32_t clearBits) { if (m_currentCommandEncoder != nil) { - // Encoder has already been created. Here we has to draw fullscreen quad for clearing. - // TODO(@rokuz,@darina) + if ((clearBits & ClearBits::ColorBit) && (clearBits & ClearBits::DepthBit)) + m_cleaner.ClearColorAndDepth(make_ref(this), m_currentCommandEncoder); + else if (clearBits & ClearBits::ColorBit) + m_cleaner.ClearColor(make_ref(this), m_currentCommandEncoder); + else if (clearBits & ClearBits::DepthBit) + m_cleaner.ClearDepth(make_ref(this), m_currentCommandEncoder); + + if (clearBits & ClearBits::StencilBit) + CHECK(false, ("Stencil clearing is not implemented")); } else { @@ -313,6 +320,14 @@ void MetalBaseContext::FinishCurrentEncoding() [m_currentCommandEncoder endEncoding]; m_currentCommandEncoder = nil; } + +void MetalBaseContext::SetSystemPrograms(drape_ptr && programClearColor, + drape_ptr && programClearDepth, + drape_ptr && programClearColorAndDepth) +{ + m_cleaner.Init(make_ref(this), std::move(programClearColor), std::move(programClearDepth), + std::move(programClearColorAndDepth)); +} } // namespace metal void RenderFrameMediator(std::function && renderFrameFunction) diff --git a/drape/metal/metal_cleaner.hpp b/drape/metal/metal_cleaner.hpp new file mode 100644 index 0000000000..81489b9096 --- /dev/null +++ b/drape/metal/metal_cleaner.hpp @@ -0,0 +1,48 @@ +#pragma once + +#import + +#include "drape/color.hpp" +#include "drape/glsl_types.hpp" +#include "drape/pointers.hpp" + +namespace dp +{ +class GpuProgram; + +namespace metal +{ +class MetalBaseContext; + +class MetalCleaner +{ +public: + MetalCleaner() = default; + + void Init(ref_ptr context, + drape_ptr && programClearColor, + drape_ptr && programClearDepth, + drape_ptr && programClearColorAndDepth); + + void SetClearColor(Color const & color); + + void ClearDepth(ref_ptr context, id encoder); + void ClearColor(ref_ptr context, id encoder); + void ClearColorAndDepth(ref_ptr context, id encoder); + +private: + void ApplyColorParam(id encoder, ref_ptr program); + void RenderQuad(ref_ptr context, id encoder, + ref_ptr program); + + id m_buffer; + id m_depthEnabledState; + id m_depthDisabledState; + glsl::vec4 m_clearColor; + + drape_ptr m_programClearColor; + drape_ptr m_programClearDepth; + drape_ptr m_programClearColorAndDepth; +}; +} // namespace metal +} // namespace dp diff --git a/drape/metal/metal_cleaner.mm b/drape/metal/metal_cleaner.mm new file mode 100644 index 0000000000..e99f57913e --- /dev/null +++ b/drape/metal/metal_cleaner.mm @@ -0,0 +1,90 @@ +#include "drape/metal/metal_cleaner.hpp" +#include "drape/metal/metal_base_context.hpp" +#include "drape/metal/metal_gpu_program.hpp" + +namespace dp +{ +namespace metal +{ +void MetalCleaner::Init(ref_ptr context, + drape_ptr && programClearColor, + drape_ptr && programClearDepth, + drape_ptr && programClearColorAndDepth) +{ + m_programClearColor = std::move(programClearColor); + m_programClearDepth = std::move(programClearDepth); + m_programClearColorAndDepth = std::move(programClearColorAndDepth); + + ref_ptr metalContext = context; + id device = metalContext->GetMetalDevice(); + std::vector quad = {-1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f}; + m_buffer = [device newBufferWithBytes:quad.data() + length:quad.size() * sizeof(quad[0]) + options:MTLResourceCPUCacheModeWriteCombined]; + m_buffer.label = @"MetalCleaner"; + + MTLDepthStencilDescriptor * desc = [[MTLDepthStencilDescriptor alloc] init]; + desc.depthWriteEnabled = YES; + desc.depthCompareFunction = MTLCompareFunctionAlways; + m_depthEnabledState = [device newDepthStencilStateWithDescriptor:desc]; + CHECK(m_depthEnabledState != nil, ()); + + desc.depthWriteEnabled = NO; + desc.depthCompareFunction = MTLCompareFunctionAlways; + m_depthDisabledState = [device newDepthStencilStateWithDescriptor:desc]; + CHECK(m_depthDisabledState != nil, ()); +} + +void MetalCleaner::SetClearColor(Color const & color) +{ + m_clearColor = glsl::ToVec4(color); +} + +void MetalCleaner::ApplyColorParam(id encoder, ref_ptr program) +{ + ref_ptr metalProgram = program; + auto const fsBindingIndex = metalProgram->GetFragmentShaderUniformsBindingIndex(); + if (fsBindingIndex >= 0) + { + [encoder setFragmentBytes:(void const *)&m_clearColor length:sizeof(m_clearColor) + atIndex:fsBindingIndex]; + } +} + +void MetalCleaner::RenderQuad(ref_ptr metalContext, id encoder, + ref_ptr program) +{ + id pipelineState = metalContext->GetPipelineState(program, false /* blendingEnabled */); + [encoder setRenderPipelineState:pipelineState]; + + [encoder setVertexBuffer:m_buffer offset:0 atIndex:0]; + [encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; +} + +void MetalCleaner::ClearDepth(ref_ptr context, id encoder) +{ + [encoder pushDebugGroup:@"ClearDepth"]; + [encoder setDepthStencilState:m_depthEnabledState]; + RenderQuad(context, encoder, make_ref(m_programClearDepth)); + [encoder popDebugGroup]; +} + +void MetalCleaner::ClearColor(ref_ptr context, id encoder) +{ + [encoder pushDebugGroup:@"ClearColor"]; + [encoder setDepthStencilState:m_depthDisabledState]; + ApplyColorParam(encoder, make_ref(m_programClearColor)); + RenderQuad(context, encoder, make_ref(m_programClearColor)); + [encoder popDebugGroup]; +} + +void MetalCleaner::ClearColorAndDepth(ref_ptr context, id encoder) +{ + [encoder pushDebugGroup:@"ClearColorAndDepth"]; + [encoder setDepthStencilState:m_depthEnabledState]; + ApplyColorParam(encoder, make_ref(m_programClearColorAndDepth)); + RenderQuad(context, encoder, make_ref(m_programClearColorAndDepth)); + [encoder popDebugGroup]; +} +} // namespace metal +} // namespace dp diff --git a/shaders/Metal/system.metal b/shaders/Metal/system.metal new file mode 100644 index 0000000000..cdbd7ef51b --- /dev/null +++ b/shaders/Metal/system.metal @@ -0,0 +1,61 @@ +#include +#include +using namespace metal; + +typedef struct +{ + packed_float2 a_position; +} Vertex_T; + +typedef struct +{ + float4 position [[position]]; +} Fragment_T; + +typedef struct +{ + float4 u_color; +} Uniforms_T; + +typedef struct +{ + float4 color [[color(0)]]; + float depth [[depth(any)]]; +} Fragment_Output; + +typedef struct +{ + float depth [[depth(any)]]; +} Fragment_DepthOutput; + +vertex Fragment_T vsCleaner(device const Vertex_T * vertices [[buffer(0)]], + ushort vid [[vertex_id]]) +{ + Fragment_T out; + out.position = float4(vertices[vid].a_position, 0.0, 1.0); + return out; +} + +fragment float4 fsClearColor(const Fragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(0)]]) +{ + return uniforms.u_color; +} + +fragment Fragment_DepthOutput fsClearDepth(const Fragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(0)]]) +{ + Fragment_DepthOutput out; + out.depth = 1.0; + return out; +} + +fragment Fragment_Output fsClearColorAndDepth(const Fragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(0)]]) +{ + Fragment_Output out; + out.color = uniforms.u_color; + out.depth = 1.0; + return out; +} + diff --git a/shaders/metal_program_pool.hpp b/shaders/metal_program_pool.hpp index 3c3dfcd899..a072c03712 100644 --- a/shaders/metal_program_pool.hpp +++ b/shaders/metal_program_pool.hpp @@ -10,6 +10,15 @@ namespace gpu { +enum class SystemProgram +{ + ClearColor = 0, + ClearDepth, + ClearColorAndDepth, + + SystemProgramsCount +}; + namespace metal { class MetalProgramPool : public ProgramPool @@ -19,8 +28,12 @@ public: ~MetalProgramPool() override; drape_ptr Get(Program program) override; - + drape_ptr GetSystemProgram(SystemProgram program); + private: + drape_ptr Get(std::string const & programName, std::string const & vertexShaderName, + std::string const & fragmentShaderName); + id GetFunction(std::string const & name); id m_device; id m_library; diff --git a/shaders/metal_program_pool.mm b/shaders/metal_program_pool.mm index 0deba17732..7377087677 100644 --- a/shaders/metal_program_pool.mm +++ b/shaders/metal_program_pool.mm @@ -22,7 +22,13 @@ struct ProgramInfo , m_fragmentShaderName(std::move(fragmentShaderName)) {} }; - + +std::array(SystemProgram::SystemProgramsCount)> const kMetalSystemProgramsInfo = {{ + ProgramInfo("vsCleaner", "fsClearColor"), // ClearColor + ProgramInfo("vsCleaner", "fsClearDepth"), // ClearDepth + ProgramInfo("vsCleaner", "fsClearColorAndDepth"), // ClearColorAndDepth +}}; + std::array(Program::ProgramsCount)> const kMetalProgramsInfo = {{ ProgramInfo("", ""), // ColoredSymbol ProgramInfo("", ""), // Texturing @@ -77,6 +83,21 @@ std::array(Program::ProgramsCount)> const kMeta }}; } // namespace +std::string DebugPrint(SystemProgram p) +{ + switch (p) + { + case SystemProgram::ClearColor: return "ClearColor"; + case SystemProgram::ClearDepth: return "ClearDepth"; + case SystemProgram::ClearColorAndDepth: return "ClearColorAndDepth"; + + case SystemProgram::SystemProgramsCount: + CHECK(false, ("Try to output SystemProgramsCount")); + } + CHECK(false, ("Unknown program")); + return {}; +} + MetalProgramPool::MetalProgramPool(id device) : m_device(device) { @@ -98,19 +119,34 @@ MetalProgramPool::~MetalProgramPool() ProgramParams::Destroy(); } +drape_ptr MetalProgramPool::GetSystemProgram(SystemProgram program) +{ + auto const & info = kMetalSystemProgramsInfo[static_cast(program)]; + return Get(DebugPrint(program), info.m_vertexShaderName, info.m_fragmentShaderName); +} + drape_ptr MetalProgramPool::Get(Program program) { auto const & info = kMetalProgramsInfo[static_cast(program)]; - CHECK(!info.m_vertexShaderName.empty(), ()); - CHECK(!info.m_fragmentShaderName.empty(), ()); - - id vertexShader = GetFunction(info.m_vertexShaderName); - id fragmentShader = GetFunction(info.m_fragmentShaderName); + return Get(DebugPrint(program), info.m_vertexShaderName, info.m_fragmentShaderName); +} + +drape_ptr MetalProgramPool::Get(std::string const & programName, + std::string const & vertexShaderName, + std::string const & fragmentShaderName) +{ + CHECK(!vertexShaderName.empty(), ()); + CHECK(!fragmentShaderName.empty(), ()); + + id vertexShader = GetFunction(vertexShaderName); + id fragmentShader = GetFunction(fragmentShaderName); MTLRenderPipelineDescriptor * desc = [[MTLRenderPipelineDescriptor alloc] init]; desc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm; + desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; desc.vertexFunction = vertexShader; desc.fragmentFunction = fragmentShader; + NSError * error = nil; MTLRenderPipelineReflection * reflectionObj = nil; MTLPipelineOption option = MTLPipelineOptionBufferTypeInfo | MTLPipelineOptionArgumentInfo; @@ -163,8 +199,7 @@ drape_ptr MetalProgramPool::Get(Program program) } } - auto const name = DebugPrint(program); - return make_unique_dp(name, vertexShader, fragmentShader, + return make_unique_dp(programName, vertexShader, fragmentShader, vsUniformsBindingIndex, fsUniformsBindingIndex, std::move(textureBindingInfo)); } @@ -176,7 +211,8 @@ id MetalProgramPool::GetFunction(std::string const & name) { id f = [m_library newFunctionWithName:@(name.c_str())]; CHECK(f != nil, ()); - f.label = [@"Function " stringByAppendingString:@(name.c_str())]; + if (@available(iOS 10.0, *)) + f.label = [@"Function " stringByAppendingString:@(name.c_str())]; m_functions.insert(std::make_pair(name, f)); return f; } diff --git a/shaders/program_manager_metal.mm b/shaders/program_manager_metal.mm index 43c3235d8c..9520234fd4 100644 --- a/shaders/program_manager_metal.mm +++ b/shaders/program_manager_metal.mm @@ -12,5 +12,10 @@ void ProgramManager::InitForMetal(ref_ptr context) ref_ptr metalContext = context; m_pool = make_unique_dp(metalContext->GetMetalDevice()); m_paramsSetter = make_unique_dp(); + + ref_ptr metalPool = make_ref(m_pool); + metalContext->SetSystemPrograms(metalPool->GetSystemProgram(SystemProgram::ClearColor), + metalPool->GetSystemProgram(SystemProgram::ClearDepth), + metalPool->GetSystemProgram(SystemProgram::ClearColorAndDepth)); } } // namespace gpu diff --git a/xcode/drape/drape.xcodeproj/project.pbxproj b/xcode/drape/drape.xcodeproj/project.pbxproj index 0379d4676a..00a788b48d 100644 --- a/xcode/drape/drape.xcodeproj/project.pbxproj +++ b/xcode/drape/drape.xcodeproj/project.pbxproj @@ -124,6 +124,8 @@ BBB72E9C2111CE9100249D4F /* graphics_context_factory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BBB72E992111CE9100249D4F /* graphics_context_factory.cpp */; }; BBB72E9F2118A45800249D4F /* mesh_object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BBB72E9D2118A45700249D4F /* mesh_object.cpp */; }; BBB72EA02118A45800249D4F /* mesh_object.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BBB72E9E2118A45800249D4F /* mesh_object.hpp */; }; + BBF7916C2142E3A100D27BD8 /* metal_cleaner.mm in Sources */ = {isa = PBXBuildFile; fileRef = BBF7916B2142E3A100D27BD8 /* metal_cleaner.mm */; }; + BBF7916E2142E42C00D27BD8 /* metal_cleaner.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BBF7916D2142E42C00D27BD8 /* metal_cleaner.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -247,6 +249,8 @@ BBB72E992111CE9100249D4F /* graphics_context_factory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphics_context_factory.cpp; sourceTree = ""; }; BBB72E9D2118A45700249D4F /* mesh_object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mesh_object.cpp; sourceTree = ""; }; BBB72E9E2118A45800249D4F /* mesh_object.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mesh_object.hpp; sourceTree = ""; }; + BBF7916B2142E3A100D27BD8 /* metal_cleaner.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = metal_cleaner.mm; sourceTree = ""; }; + BBF7916D2142E42C00D27BD8 /* metal_cleaner.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = metal_cleaner.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -275,6 +279,8 @@ 4598438D2139967F00F8CAB2 /* metal_texture.mm */, 4560F5A6214297D800CC736C /* metal_vertex_array_buffer_impl.mm */, 4560F590213EC93300CC736C /* render_state_metal.mm */, + BBF7916B2142E3A100D27BD8 /* metal_cleaner.mm */, + BBF7916D2142E42C00D27BD8 /* metal_cleaner.hpp */, ); path = metal; sourceTree = ""; @@ -449,6 +455,7 @@ 45447109211462A300D28C28 /* texture_types.hpp in Headers */, BBB72EA02118A45800249D4F /* mesh_object.hpp in Headers */, 675D219A1BFB876E00717E4F /* projection.hpp in Headers */, + BBF7916E2142E42C00D27BD8 /* metal_cleaner.hpp in Headers */, 45789EF6213557F7009955CC /* gl_includes.hpp in Headers */, 45789EF9213557F7009955CC /* gl_functions.hpp in Headers */, 670947291BDF9A4F005014C0 /* hw_texture_ios.hpp in Headers */, @@ -554,6 +561,7 @@ 6729A5631A69213A007D5872 /* attribute_buffer_mutator.cpp in Sources */, 6729A56B1A69213A007D5872 /* binding_info.cpp in Sources */, BBB72E9F2118A45800249D4F /* mesh_object.cpp in Sources */, + BBF7916C2142E3A100D27BD8 /* metal_cleaner.mm in Sources */, 45789EF5213557F7009955CC /* gl_gpu_program.cpp in Sources */, 45789EF3213557F7009955CC /* gl_extensions_list.cpp in Sources */, 6729A5941A69213A007D5872 /* overlay_handle.cpp in Sources */, diff --git a/xcode/shaders/shaders.xcodeproj/project.pbxproj b/xcode/shaders/shaders.xcodeproj/project.pbxproj index cfa831da84..46a63ed36c 100644 --- a/xcode/shaders/shaders.xcodeproj/project.pbxproj +++ b/xcode/shaders/shaders.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 45789EE021343F70009955CC /* metal_program_pool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45789EDE21343F70009955CC /* metal_program_pool.mm */; }; 45789EE421353CA3009955CC /* program_manager_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45789EE321353CA3009955CC /* program_manager_metal.mm */; }; 45789EE72135464D009955CC /* metal_program_params.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45789EE62135464D009955CC /* metal_program_params.mm */; }; + BBF791702146D8EC00D27BD8 /* system.metal in Sources */ = {isa = PBXBuildFile; fileRef = BBF7916F2146D8EC00D27BD8 /* system.metal */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -171,6 +172,7 @@ 45789EE52135464D009955CC /* metal_program_params.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = metal_program_params.hpp; sourceTree = ""; }; 45789EE62135464D009955CC /* metal_program_params.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = metal_program_params.mm; sourceTree = ""; }; 4598437C21394BE000F8CAB2 /* shaders_metal.metallib */ = {isa = PBXFileReference; explicitFileType = "archive.metal-library"; includeInIndex = 0; path = shaders_metal.metallib; sourceTree = BUILT_PRODUCTS_DIR; }; + BBF7916F2146D8EC00D27BD8 /* system.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = system.metal; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -373,6 +375,7 @@ 45789EDC21342BDE009955CC /* debug_rect.metal */, 4560F582213D44CE00CC736C /* screen_quad.metal */, 4560F5AA2142AC1300CC736C /* gui.metal */, + BBF7916F2146D8EC00D27BD8 /* system.metal */, ); path = Metal; sourceTree = ""; @@ -531,6 +534,7 @@ buildActionMask = 2147483647; files = ( 4560F5AB2142AC1300CC736C /* gui.metal in Sources */, + BBF791702146D8EC00D27BD8 /* system.metal in Sources */, 4560F58A213D57D600CC736C /* debug_rect.metal in Sources */, 4560F58B213D57D600CC736C /* screen_quad.metal in Sources */, );