Add buffer/image binding for compute, and add histogram construction
This commit is contained in:
parent
267f6221bf
commit
4b4fc0b00d
7 changed files with 85 additions and 34 deletions
|
@ -673,6 +673,8 @@ GFXPipeline* GFXMetal::create_compute_pipeline(const GFXComputePipelineCreateInf
|
|||
MTLComputePipelineDescriptor* pipelineDescriptor = [MTLComputePipelineDescriptor new];
|
||||
pipelineDescriptor.computeFunction = computeFunc;
|
||||
|
||||
pipeline->threadGroupSize = MTLSizeMake(info.workgroup_size_x, info.workgroup_size_y, info.workgroup_size_z);
|
||||
|
||||
if(debug_enabled) {
|
||||
pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()];
|
||||
pipeline->label = info.label;
|
||||
|
@ -881,29 +883,33 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const int window) {
|
|||
break;
|
||||
case GFXCommandType::BindShaderBuffer:
|
||||
{
|
||||
needEncoder(CurrentEncoder::Render);
|
||||
|
||||
[renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ];
|
||||
|
||||
[renderEncoder setFragmentBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ];
|
||||
if(current_encoder == CurrentEncoder::Render) {
|
||||
[renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ];
|
||||
|
||||
[renderEncoder setFragmentBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ];
|
||||
} else if(current_encoder == CurrentEncoder::Compute) {
|
||||
[computeEncoder setBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GFXCommandType::BindTexture:
|
||||
{
|
||||
needEncoder(CurrentEncoder::Render);
|
||||
if(current_encoder == CurrentEncoder::Render) {
|
||||
if(command.data.bind_texture.texture != nullptr) {
|
||||
[renderEncoder setVertexSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setVertexTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setFragmentSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
if(command.data.bind_texture.texture != nullptr) {
|
||||
[renderEncoder setVertexSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setVertexTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setFragmentSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setFragmentTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
} else {
|
||||
[renderEncoder setVertexTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setFragmentTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
[renderEncoder setFragmentTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
} else {
|
||||
[renderEncoder setVertexTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
|
||||
[renderEncoder setFragmentTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
}
|
||||
} else if(current_encoder == CurrentEncoder::Compute) {
|
||||
[computeEncoder setTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1066,15 +1072,8 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const int window) {
|
|||
break;
|
||||
case GFXCommandType::Dispatch: {
|
||||
needEncoder(CurrentEncoder::Compute);
|
||||
|
||||
NSUInteger threadGroupSize = currentPipeline->compute_handle.maxTotalThreadsPerThreadgroup;
|
||||
|
||||
MTLSize threadgroupSize = MTLSizeMake(std::min(threadGroupSize,
|
||||
(NSUInteger)command.data.dispatch.group_count_x),
|
||||
std::min(threadGroupSize, (NSUInteger)command.data.dispatch.group_count_y),
|
||||
std::min(threadGroupSize, (NSUInteger)command.data.dispatch.group_count_z));
|
||||
|
||||
[computeEncoder dispatchThreads:MTLSizeMake(command.data.dispatch.group_count_x, command.data.dispatch.group_count_y, command.data.dispatch.group_count_z) threadsPerThreadgroup:threadgroupSize];
|
||||
[computeEncoder dispatchThreads:MTLSizeMake(command.data.dispatch.group_count_x, command.data.dispatch.group_count_y, command.data.dispatch.group_count_z) threadsPerThreadgroup:currentPipeline->threadGroupSize];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ public:
|
|||
|
||||
id<MTLRenderPipelineState> handle = nil;
|
||||
id<MTLComputePipelineState> compute_handle = nil;
|
||||
|
||||
MTLSize threadGroupSize;
|
||||
|
||||
id<MTLDepthStencilState> depthStencil = nil;
|
||||
MTLPrimitiveType primitiveType;
|
||||
|
|
|
@ -201,6 +201,9 @@ struct GFXComputePipelineCreateInfo {
|
|||
std::string_view compute_path;
|
||||
ShaderSource compute_src;
|
||||
} shaders;
|
||||
|
||||
// TODO: extract this from the shader instead of hardcoding it twice (once in GLSL, and now here)
|
||||
int workgroup_size_x = 1, workgroup_size_y = 1, workgroup_size_z = 1;
|
||||
};
|
||||
|
||||
struct GFXFramebufferCreateInfo {
|
||||
|
|
|
@ -180,6 +180,7 @@ private:
|
|||
|
||||
// histogram compute
|
||||
GFXPipeline* histogram_pipeline = nullptr;
|
||||
GFXBuffer* histogram_buffer = nullptr;
|
||||
|
||||
std::unique_ptr<SMAAPass> smaaPass;
|
||||
std::unique_ptr<GaussianHelper> gHelper;
|
||||
|
|
|
@ -205,10 +205,6 @@ void Renderer::stopSceneBlur() {
|
|||
|
||||
void Renderer::render(Scene* scene, int index) {
|
||||
GFXCommandBuffer* commandbuffer = engine->get_gfx()->acquire_command_buffer();
|
||||
|
||||
commandbuffer->set_compute_pipeline(histogram_pipeline);
|
||||
|
||||
commandbuffer->dispatch(1, 1, 1);
|
||||
|
||||
const auto extent = get_extent();
|
||||
const auto render_extent = get_render_extent();
|
||||
|
@ -289,6 +285,14 @@ void Renderer::render(Scene* scene, int index) {
|
|||
commandbuffer->set_viewport(viewport);
|
||||
|
||||
commandbuffer->push_group("Post Processing");
|
||||
|
||||
commandbuffer->set_compute_pipeline(histogram_pipeline);
|
||||
|
||||
commandbuffer->bind_texture(offscreenColorTexture, 0);
|
||||
commandbuffer->bind_shader_buffer(histogram_buffer, 0, 1, sizeof(uint) * 256);
|
||||
|
||||
commandbuffer->dispatch(static_cast<uint32_t>(std::ceil(render_extent.width / 16.0f)),
|
||||
static_cast<uint32_t>(std::ceil(render_extent.height / 16.0f)), 1);
|
||||
|
||||
commandbuffer->set_graphics_pipeline(viewport_mode ? renderToViewportPipeline : postPipeline);
|
||||
commandbuffer->bind_texture(offscreenColorTexture, 1);
|
||||
|
@ -1003,6 +1007,10 @@ void Renderer::createBRDF() {
|
|||
void Renderer::create_histogram_resources() {
|
||||
GFXComputePipelineCreateInfo create_info = {};
|
||||
create_info.shaders.compute_path = "histogram.comp";
|
||||
create_info.workgroup_size_x = 16;
|
||||
create_info.workgroup_size_y = 16;
|
||||
|
||||
histogram_pipeline = gfx->create_compute_pipeline(create_info);
|
||||
|
||||
histogram_buffer = gfx->create_buffer(nullptr, sizeof(uint) * 256, false, GFXBufferUsage::Storage);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.005;
|
||||
|
||||
const vec2 PoissonOffsets[64] = {
|
||||
vec2(0.0617981, 0.07294159),
|
||||
|
@ -157,4 +158,4 @@ vec3 from_srgb_to_linear(const vec3 sRGB) {
|
|||
vec3 lower = sRGB/vec3(12.92);
|
||||
|
||||
return mix(higher, lower, cutoff);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,47 @@
|
|||
#include "common.nocompile.glsl"
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 16) in;
|
||||
|
||||
layout(rgba32f, binding = 0) uniform image2D hdr_image;
|
||||
|
||||
// adapated from https://bruop.github.io/exposure/ and http://www.alextardif.com/HistogramLuminance.html
|
||||
|
||||
// Taken from RTR vol 4 pg. 278
|
||||
#define RGB_TO_LUM vec3(0.2125, 0.7154, 0.0721)
|
||||
|
||||
shared uint histogram_shared[256];
|
||||
|
||||
void main() {
|
||||
histogram_shared[gl_LocalInvocationIndex] = 1;
|
||||
groupMemoryBarrier();
|
||||
layout(std430, binding = 1) buffer HistogramBuffer {
|
||||
uint histogram[];
|
||||
};
|
||||
|
||||
const vec4 params = vec4(-10.0, 1.0 / 12.0, 0.0, 0.0);
|
||||
|
||||
uint color_to_bin(const vec3 hdr_color, const float min_log_lum, const float inverse_log_lum_range) {
|
||||
const float lum = dot(hdr_color, RGB_TO_LUM);
|
||||
|
||||
if (lum < EPSILON) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const float log_lum = clamp((log2(lum) - min_log_lum) * inverse_log_lum_range, 0.0, 1.0);
|
||||
|
||||
return uint(log_lum * 254.0 + 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
histogram_shared[gl_LocalInvocationIndex] = 0;
|
||||
groupMemoryBarrier();
|
||||
|
||||
uvec2 dim = imageSize(hdr_image).xy;
|
||||
if(gl_GlobalInvocationID.x < dim.x && gl_GlobalInvocationID.y < dim.y) {
|
||||
vec3 hdr_color = imageLoad(hdr_image, ivec2(gl_GlobalInvocationID.xy)).xyz;
|
||||
uint bin_index = color_to_bin(hdr_color, params.x, params.y);
|
||||
|
||||
atomicAdd(histogram_shared[bin_index], 1);
|
||||
}
|
||||
|
||||
groupMemoryBarrier();
|
||||
|
||||
atomicAdd(histogram[gl_LocalInvocationIndex], histogram_shared[gl_LocalInvocationIndex]);
|
||||
}
|
||||
|
|
Reference in a new issue