mirror of
https://github.com/love2d/love.git
synced 2026-08-15 15:51:12 +02:00
metal: work towards shader uniform implementation.
Misc cleanup.
This commit is contained in:
@@ -472,7 +472,7 @@ public:
|
||||
* @param width The viewport width.
|
||||
* @param height The viewport height.
|
||||
**/
|
||||
virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil) = 0;
|
||||
virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int backbufferdepth) = 0;
|
||||
|
||||
/**
|
||||
* Un-sets the current graphics display mode (uninitializing objects if
|
||||
|
||||
@@ -95,6 +95,7 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settin
|
||||
Buffer::~Buffer()
|
||||
{ @autoreleasepool {
|
||||
buffer = nil;
|
||||
texture = nil;
|
||||
}}
|
||||
|
||||
void *Buffer::map()
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) override;
|
||||
|
||||
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
|
||||
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil) override;
|
||||
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int backbufferdepth) override;
|
||||
void unSetMode() override;
|
||||
|
||||
void setActive(bool active) override;
|
||||
@@ -195,6 +195,8 @@ private:
|
||||
std::map<uint64, void *> cachedSamplers;
|
||||
std::unordered_map<uint64, void *> cachedDepthStencilStates;
|
||||
|
||||
std::atomic<int64> completeCommandBufferIndex;
|
||||
|
||||
}; // Graphics
|
||||
|
||||
} // metal
|
||||
|
||||
@@ -112,6 +112,21 @@ static MTLStencilOperation getMTLStencilOperation(StencilAction action)
|
||||
return MTLStencilOperationKeep;
|
||||
}
|
||||
|
||||
static inline id<MTLTexture> getMTLTexture(love::graphics::Texture *tex)
|
||||
{
|
||||
return tex ? (__bridge id<MTLTexture>)(void *) tex->getHandle() : nil;
|
||||
}
|
||||
|
||||
static inline id<MTLTexture> getMTLRenderTarget(love::graphics::Texture *tex)
|
||||
{
|
||||
return tex ? (__bridge id<MTLTexture>)(void *) tex->getRenderTargetHandle() : nil;
|
||||
}
|
||||
|
||||
static inline id<MTLBuffer> getMTLBuffer(love::graphics::Resource *res)
|
||||
{
|
||||
return res ? (__bridge id<MTLBuffer>)(void *) res->getHandle() : nil;
|
||||
}
|
||||
|
||||
love::graphics::Graphics *createInstance()
|
||||
{
|
||||
love::graphics::Graphics *instance = nullptr;
|
||||
@@ -190,7 +205,7 @@ Graphics::Graphics()
|
||||
window->windowToDPICoords(&dpiW, &dpiH);
|
||||
|
||||
void *context = nullptr; // TODO
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil);
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil, settings.depth);
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -257,18 +272,18 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
|
||||
}
|
||||
}
|
||||
|
||||
bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil)
|
||||
bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int backbufferdepth)
|
||||
{ @autoreleasepool {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->metalLayer = (__bridge CAMetalLayer *) context;
|
||||
|
||||
this->windowHasStencil = windowhasstencil;
|
||||
this->windowHasStencil = backbufferstencil;
|
||||
|
||||
metalLayer.device = device;
|
||||
metalLayer.pixelFormat = isGammaCorrect() ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
|
||||
|
||||
// TODO: set to NO when we have pending screen captures
|
||||
// This is set to NO when there are pending screen captures.
|
||||
metalLayer.framebufferOnly = YES;
|
||||
|
||||
setViewportSize(width, height, pixelwidth, pixelheight);
|
||||
@@ -338,8 +353,17 @@ void Graphics::setActive(bool enable)
|
||||
id<MTLCommandBuffer> Graphics::useCommandBuffer()
|
||||
{
|
||||
if (commandBuffer == nil)
|
||||
{
|
||||
commandBuffer = [commandQueue commandBuffer];
|
||||
|
||||
Graphics *pthis = this;
|
||||
pthis->retain();
|
||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
|
||||
pthis->completeCommandBufferIndex.fetch_add(1, std::memory_order_relaxed);
|
||||
pthis->release();
|
||||
}];
|
||||
}
|
||||
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
@@ -361,21 +385,30 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
||||
{
|
||||
submitBlitEncoder();
|
||||
|
||||
// Pass desc info for non-backbuffer render targets are set up in
|
||||
// setRenderTagetsInternal.
|
||||
const auto &rts = states.back().renderTargets;
|
||||
if (rts.getFirstTarget().texture.get() != nullptr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
if (rts.getFirstTarget().texture.get() == nullptr)
|
||||
{
|
||||
if (activeDrawable == nil)
|
||||
{
|
||||
// This is reset to YES after each frame.
|
||||
// TODO: Does setting this reallocate memory?
|
||||
if (!pendingScreenshotCallbacks.empty())
|
||||
metalLayer.framebufferOnly = NO;
|
||||
|
||||
activeDrawable = [metalLayer nextDrawable];
|
||||
}
|
||||
|
||||
passDesc.colorAttachments[0].texture = activeDrawable.texture;
|
||||
passDesc.colorAttachments[0].level = 0;
|
||||
passDesc.colorAttachments[0].slice = 0;
|
||||
passDesc.colorAttachments[0].depthPlane = 0;
|
||||
}
|
||||
|
||||
renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc];
|
||||
|
||||
id<MTLBuffer> defaultbuffer = (__bridge id<MTLBuffer>)(void *)defaultAttributesBuffer->getHandle();
|
||||
id<MTLBuffer> defaultbuffer = getMTLBuffer(defaultAttributesBuffer);
|
||||
[renderEncoder setVertexBuffer:defaultbuffer offset:0 atIndex:DEFAULT_VERTEX_BUFFER_BINDING];
|
||||
|
||||
dirtyRenderState = STATEBIT_ALL;
|
||||
@@ -622,37 +655,33 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
size_t alignment = 16;
|
||||
#endif
|
||||
|
||||
// TODO: use the size of all uniforms
|
||||
size_t size = sizeof(Shader::BuiltinUniformData);
|
||||
size_t size = s->getLocalUniformBufferSize();
|
||||
uint8 *bufferdata = s->getLocalUniformBufferData();
|
||||
|
||||
Shader::BuiltinUniformData data;
|
||||
auto builtins = (Shader::BuiltinUniformData *) (bufferdata + s->getBuiltinUniformDataOffset());
|
||||
|
||||
data.transformMatrix = getTransform();
|
||||
data.projectionMatrix = getProjection();
|
||||
builtins->transformMatrix = getTransform();
|
||||
builtins->projectionMatrix = getProjection();
|
||||
|
||||
// The normal matrix is the transpose of the inverse of the rotation portion
|
||||
// (top-left 3x3) of the transform matrix.
|
||||
{
|
||||
Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse();
|
||||
Matrix3 normalmatrix = Matrix3(builtins->transformMatrix).transposedInverse();
|
||||
const float *e = normalmatrix.getElements();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
data.normalMatrix[i].x = e[i * 3 + 0];
|
||||
data.normalMatrix[i].y = e[i * 3 + 1];
|
||||
data.normalMatrix[i].z = e[i * 3 + 2];
|
||||
data.normalMatrix[i].w = 0.0f;
|
||||
builtins->normalMatrix[i].x = e[i * 3 + 0];
|
||||
builtins->normalMatrix[i].y = e[i * 3 + 1];
|
||||
builtins->normalMatrix[i].z = e[i * 3 + 2];
|
||||
builtins->normalMatrix[i].w = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: should be active RT dimensions
|
||||
data.screenSizeParams.x = getPixelWidth();
|
||||
data.screenSizeParams.y = getPixelHeight();
|
||||
builtins->screenSizeParams = Vector4(getPixelWidth(), getPixelHeight(), 1.0f, 0.0f);
|
||||
|
||||
data.screenSizeParams.z = 1.0f;
|
||||
data.screenSizeParams.w = 0.0f;
|
||||
|
||||
data.constantColor = getColor();
|
||||
gammaCorrectColor(data.constantColor);
|
||||
builtins->constantColor = getColor();
|
||||
gammaCorrectColor(builtins->constantColor);
|
||||
|
||||
if (uniformBuffer->getSize() < uniformBufferOffset + size)
|
||||
{
|
||||
@@ -666,9 +695,9 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
if (uniformBufferData.data == nullptr)
|
||||
uniformBufferData = uniformBuffer->map(uniformBuffer->getSize());
|
||||
|
||||
memcpy(uniformBufferData.data + uniformBufferOffset, &data, sizeof(Shader::BuiltinUniformData));
|
||||
memcpy(uniformBufferData.data + uniformBufferOffset, bufferdata, size);
|
||||
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)uniformBuffer->getHandle();
|
||||
id<MTLBuffer> buffer = getMTLBuffer(uniformBuffer);
|
||||
int index = Shader::getUniformBufferBinding();
|
||||
|
||||
// TODO: bind shader textures/samplers
|
||||
@@ -679,6 +708,26 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
uniformBufferOffset += alignUp(size, alignment);
|
||||
}
|
||||
|
||||
static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBindings *buffers)
|
||||
{
|
||||
uint32 allbits = buffers->useBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (buffers->useBits & bit)
|
||||
{
|
||||
auto b = buffers->info[i];
|
||||
id<MTLBuffer> buffer = getMTLBuffer(b.buffer);
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::draw(const DrawCommand &cmd)
|
||||
{ @autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||
@@ -690,29 +739,14 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
||||
|
||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
uint32 allbits = cmd.buffers->useBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (cmd.buffers->useBits & bit)
|
||||
{
|
||||
auto b = cmd.buffers->info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
}
|
||||
setVertexBuffers(encoder, cmd.buffers);
|
||||
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangle
|
||||
vertexStart:cmd.vertexStart
|
||||
@@ -731,36 +765,21 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
||||
|
||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
uint32 allbits = cmd.buffers->useBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (cmd.buffers->useBits & bit)
|
||||
{
|
||||
auto b = cmd.buffers->info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
}
|
||||
setVertexBuffers(encoder, cmd.buffers);
|
||||
|
||||
auto indexType = cmd.indexType == INDEX_UINT32 ? MTLIndexTypeUInt32 : MTLIndexTypeUInt16;
|
||||
|
||||
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:cmd.indexCount
|
||||
indexType:indexType
|
||||
indexBuffer:(__bridge id<MTLBuffer>)(void*)cmd.indexBuffer->getHandle()
|
||||
indexBuffer:getMTLBuffer(cmd.indexBuffer)
|
||||
indexBufferOffset:cmd.indexBufferOffset
|
||||
instanceCount:cmd.instanceCount];
|
||||
}}
|
||||
@@ -778,31 +797,16 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
||||
|
||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
uint32 allbits = buffers.useBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
setVertexBuffers(encoder, &buffers);
|
||||
|
||||
if (buffers.useBits & bit)
|
||||
{
|
||||
auto b = buffers.info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
}
|
||||
|
||||
id<MTLBuffer> ib = (__bridge id<MTLBuffer>)(void *) quadIndexBuffer->getHandle();
|
||||
id<MTLBuffer> ib = getMTLBuffer(quadIndexBuffer);
|
||||
|
||||
// TODO: support for iOS devices that don't support base vertex.
|
||||
|
||||
@@ -827,56 +831,60 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
||||
}
|
||||
}}
|
||||
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas)
|
||||
{ @autoreleasepool {
|
||||
const DisplayState &state = states.back();
|
||||
static inline void setAttachment(const Graphics::RenderTarget &rt, MTLRenderPassAttachmentDescriptor *desc)
|
||||
{
|
||||
bool isvolume = rt.texture->getTextureType() == TEXTURE_VOLUME;
|
||||
|
||||
desc.texture = getMTLRenderTarget(rt.texture);
|
||||
desc.level = rt.mipmap;
|
||||
desc.slice = isvolume ? 0 : rt.slice;
|
||||
desc.depthPlane = isvolume ? rt.slice : 0;
|
||||
|
||||
// Default to load until clear or discard is called.
|
||||
desc.loadAction = MTLLoadActionLoad;
|
||||
desc.storeAction = MTLStoreActionStore;
|
||||
|
||||
desc.resolveTexture = nil;
|
||||
|
||||
if (rt.texture->getMSAA() > 1)
|
||||
{
|
||||
// TODO
|
||||
desc.resolveTexture = getMTLTexture(rt.texture);
|
||||
|
||||
// TODO: This StoreAction is only supported sometimes.
|
||||
desc.storeAction = MTLStoreActionStoreAndMultisampleResolve;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int /*pixelw*/, int /*pixelh*/, bool /*hasSRGBtexture*/)
|
||||
{ @autoreleasepool {
|
||||
endPass();
|
||||
|
||||
// Set up render pass descriptor for the next useRenderEncoder call.
|
||||
// The backbuffer will be set up in useRenderEncoder rather than here.
|
||||
for (size_t i = 0; i < rts.colors.size(); i++)
|
||||
{
|
||||
auto rt = rts.colors[i];
|
||||
auto tex = rt.texture;
|
||||
auto desc = passDesc.colorAttachments[i];
|
||||
|
||||
desc.texture = (__bridge id<MTLTexture>)(void*)tex->getRenderTargetHandle();
|
||||
desc.level = rt.mipmap;
|
||||
|
||||
if (tex->getTextureType() == TEXTURE_VOLUME)
|
||||
{
|
||||
desc.slice = 0;
|
||||
desc.depthPlane = rt.slice;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.slice = rt.slice;
|
||||
desc.depthPlane = 0;
|
||||
}
|
||||
|
||||
// Default to load until clear or discard is called.
|
||||
desc.loadAction = MTLLoadActionLoad;
|
||||
desc.storeAction = MTLStoreActionStore;
|
||||
|
||||
desc.resolveTexture = nil;
|
||||
|
||||
if (tex->getMSAA() > 1)
|
||||
{
|
||||
// TODO
|
||||
desc.resolveTexture = (__bridge id<MTLTexture>)(void*)tex->getHandle();
|
||||
|
||||
// TODO: This StoreAction is only supported sometimes.
|
||||
desc.storeAction = MTLStoreActionStoreAndMultisampleResolve;
|
||||
}
|
||||
|
||||
setAttachment(rts.colors[i], desc);
|
||||
passDesc.colorAttachments[i] = desc;
|
||||
}
|
||||
|
||||
for (size_t i = rts.colors.size(); i < MAX_COLOR_RENDER_TARGETS; i++)
|
||||
passDesc.colorAttachments[i] = nil;
|
||||
|
||||
// TODO: depth/stencil attachments
|
||||
// TODO: projection matrix
|
||||
// TODO: backbuffer
|
||||
passDesc.depthAttachment = nil;
|
||||
passDesc.stencilAttachment = nil;
|
||||
|
||||
if (rts.depthStencil.texture)
|
||||
{
|
||||
if (isPixelFormatDepth(rts.depthStencil.texture->getPixelFormat()))
|
||||
setAttachment(rts.depthStencil, passDesc.depthAttachment);
|
||||
|
||||
if (isPixelFormatStencil(rts.depthStencil.texture->getPixelFormat()))
|
||||
setAttachment(rts.depthStencil, passDesc.stencilAttachment);
|
||||
}
|
||||
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) w, (float) h, 0.0, -10.0f, 10.0f);
|
||||
dirtyRenderState = STATEBIT_ALL;
|
||||
}}
|
||||
|
||||
@@ -1093,6 +1101,9 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
if (window != nullptr)
|
||||
window->swapBuffers();
|
||||
|
||||
// This is set to NO when there are pending screen captures.
|
||||
metalLayer.framebufferOnly = YES;
|
||||
|
||||
activeDrawable = nil;
|
||||
|
||||
// Reset the per-frame stat counts.
|
||||
|
||||
@@ -76,10 +76,10 @@ public:
|
||||
int getVertexAttributeIndex(const std::string &name) override;
|
||||
const UniformInfo *getUniformInfo(const std::string &name) const override;
|
||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
||||
void updateUniform(const UniformInfo *info, int count) override {}
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override {}
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override {}
|
||||
bool hasUniform(const std::string &name) const override { return false; }
|
||||
void updateUniform(const UniformInfo *info, int count) override;
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override;
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override;
|
||||
bool hasUniform(const std::string &name) const override;
|
||||
ptrdiff_t getHandle() const override { return 0; }
|
||||
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override {}
|
||||
|
||||
@@ -89,6 +89,7 @@ public:
|
||||
|
||||
uint8 *getLocalUniformBufferData() { return localUniformBufferData; }
|
||||
size_t getLocalUniformBufferSize() const { return localUniformBufferSize; }
|
||||
size_t getBuiltinUniformDataOffset() const { return builtinUniformDataOffset; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -107,6 +108,7 @@ private:
|
||||
|
||||
uint8 *localUniformBufferData;
|
||||
size_t localUniformBufferSize;
|
||||
size_t builtinUniformDataOffset;
|
||||
|
||||
std::map<std::string, int> attributes;
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
, builtinUniformInfo()
|
||||
, localUniformBufferData(nullptr)
|
||||
, localUniformBufferSize(0)
|
||||
, builtinUniformDataOffset(0)
|
||||
{ @autoreleasepool {
|
||||
using namespace glslang;
|
||||
using namespace spirv_cross;
|
||||
@@ -166,11 +167,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
opt.validate = true;
|
||||
|
||||
std::vector<unsigned int> spirv;
|
||||
|
||||
{
|
||||
// timer::ScopedTimer("shader stage");
|
||||
GlslangToSpv(*intermediate, spirv, &logger, &opt);
|
||||
}
|
||||
GlslangToSpv(*intermediate, spirv, &logger, &opt);
|
||||
|
||||
std::string msgs = logger.getAllMessages();
|
||||
// printf("spirv length: %ld, messages:\n%s\n", spirv.size(), msgs.c_str());
|
||||
@@ -203,28 +200,99 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
{
|
||||
if (it->second.ints[0] != binding)
|
||||
throw love::Exception("texture binding mismatch for %s: %d vs %d", resource.name.c_str(), it->second.ints[0], binding);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
UniformInfo u = {};
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.name = resource.name;
|
||||
u.location = 0;
|
||||
u.textures = new love::graphics::Texture*[1];
|
||||
u.textures[0] = nullptr;
|
||||
u.data = malloc(sizeof(int) * 1);
|
||||
u.ints[0] = binding;
|
||||
// printf("binding for %s: %d\n", u.name.c_str(), binding);
|
||||
|
||||
uniforms[u.name] = u;
|
||||
}
|
||||
UniformInfo u = {};
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.name = resource.name;
|
||||
u.location = 0;
|
||||
u.textures = new love::graphics::Texture*[1];
|
||||
u.textures[0] = nullptr;
|
||||
u.data = malloc(sizeof(int) * 1);
|
||||
u.ints[0] = binding;
|
||||
// printf("binding for %s: %d\n", u.name.c_str(), binding);
|
||||
|
||||
uniforms[u.name] = u;
|
||||
}
|
||||
|
||||
for (const auto &resource : resources.uniform_buffers)
|
||||
{
|
||||
auto it = uniforms.find(resource.name);
|
||||
if (it != uniforms.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resource.name == "love_UniformsPerDrawBuffer")
|
||||
{
|
||||
msl.set_decoration(resource.id, spv::DecorationBinding, 0);
|
||||
const SPIRType &type = msl.get_type(resource.base_type_id);
|
||||
const auto &membertypes = type.member_types;
|
||||
|
||||
size_t size = msl.get_declared_struct_size(type);
|
||||
|
||||
if (localUniformBufferSize != 0)
|
||||
{
|
||||
if (localUniformBufferSize != size)
|
||||
throw love::Exception("Local uniform buffer size mismatch");
|
||||
continue;
|
||||
}
|
||||
|
||||
localUniformBufferData = new uint8[size];
|
||||
localUniformBufferSize = size;
|
||||
|
||||
memset(localUniformBufferData, 0, size);
|
||||
|
||||
for (size_t uindex = 0; uindex < membertypes.size(); uindex++)
|
||||
{
|
||||
const auto &membertype = msl.get_type(membertypes[uindex]);
|
||||
size_t membersize = msl.get_declared_struct_member_size(type, uindex);
|
||||
size_t offset = msl.type_struct_member_offset(type, uindex);
|
||||
|
||||
UniformInfo u = {};
|
||||
u.name = msl.get_name(membertypes[uindex]);
|
||||
u.dataSize = membersize;
|
||||
u.count = std::max<size_t>(1, membertype.array.size());
|
||||
|
||||
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
||||
if (getConstant(u.name.c_str(), builtin))
|
||||
{
|
||||
if (builtin == BUILTIN_UNIFORMS_PER_DRAW)
|
||||
builtinUniformDataOffset = offset;
|
||||
}
|
||||
|
||||
switch (membertype.basetype)
|
||||
{
|
||||
case SPIRType::Int:
|
||||
case SPIRType::UInt:
|
||||
case SPIRType::Float:
|
||||
u.data = localUniformBufferData + offset;
|
||||
if (membertype.columns == 1)
|
||||
{
|
||||
if (membertype.basetype == SPIRType::Int)
|
||||
u.baseType = UNIFORM_INT;
|
||||
else if (membertype.basetype == SPIRType::UInt)
|
||||
u.baseType = UNIFORM_UINT;
|
||||
else
|
||||
u.baseType = UNIFORM_FLOAT;
|
||||
u.components = membertype.vecsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
u.baseType = UNIFORM_MATRIX;
|
||||
u.matrix.rows = membertype.vecsize;
|
||||
u.matrix.columns = membertype.columns;
|
||||
}
|
||||
break;
|
||||
case SPIRType::Struct:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,10 +315,14 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
}
|
||||
}
|
||||
|
||||
printf("ubos: %d, storage: %d, inputs: %d, outputs: %d, images: %d, samplers: %d, push: %d\n", resources.uniform_buffers.size(), resources.storage_buffers.size(), resources.stage_inputs.size(), resources.stage_outputs.size(), resources.storage_images.size(), resources.sampled_images.size(), resources.push_constant_buffers.size());
|
||||
printf("// ubos: %ld, storage: %ld, inputs: %ld, outputs: %ld, images: %ld, samplers: %ld, push: %ld\n", resources.uniform_buffers.size(), resources.storage_buffers.size(), resources.stage_inputs.size(), resources.stage_outputs.size(), resources.storage_images.size(), resources.sampled_images.size(), resources.push_constant_buffers.size());
|
||||
|
||||
CompilerMSL::Options options;
|
||||
|
||||
options.set_msl_version(2, 1);
|
||||
|
||||
options.texture_buffer_native = true;
|
||||
|
||||
#ifdef LOVE_IOS
|
||||
options.platform = CompilerMSL::Options::iOS;
|
||||
#else
|
||||
@@ -260,7 +332,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
msl.set_msl_options(options);
|
||||
|
||||
std::string source = msl.compile();
|
||||
// printf("MSL SOURCE for stage %d:\n\n%s\n\n", i, source.c_str());
|
||||
// printf("// MSL SOURCE for stage %d:\n\n%s\n\n", i, source.c_str());
|
||||
|
||||
NSString *nssource = [[NSString alloc] initWithBytes:source.c_str()
|
||||
length:source.length()
|
||||
@@ -280,6 +352,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
||||
{
|
||||
spv::StorageClass storage = msl.get_storage_class(var);
|
||||
const std::string &name = msl.get_name(var);
|
||||
printf("var: %s\n", name.c_str());
|
||||
|
||||
if (i == ShaderStage::STAGE_VERTEX && storage == spv::StorageClassInput)
|
||||
attributes[name] = msl.get_decoration(var, spv::DecorationLocation);
|
||||
@@ -338,6 +411,27 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
|
||||
return builtinUniformInfo[(int)builtin];
|
||||
}
|
||||
|
||||
void Shader::updateUniform(const UniformInfo * /*info*/, int /*count*/)
|
||||
{
|
||||
// Nothing needed here, All uniform data will be memcpy'd to the main
|
||||
// uniform buffer before drawing.
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
bool Shader::hasUniform(const std::string &name) const
|
||||
{
|
||||
return uniforms.find(name) != uniforms.end();
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineKey &key)
|
||||
{
|
||||
auto it = cachedRenderPipelines.find(key);
|
||||
|
||||
@@ -129,7 +129,7 @@ Graphics::Graphics()
|
||||
window->windowToDPICoords(&dpiW, &dpiH);
|
||||
|
||||
void *context = nullptr; // TODO
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil);
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil, settings.depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,12 +190,12 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
|
||||
}
|
||||
}
|
||||
|
||||
bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil)
|
||||
bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int /*backbufferdepth*/)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
|
||||
this->windowHasStencil = windowhasstencil;
|
||||
this->windowHasStencil = backbufferstencil;
|
||||
|
||||
// Okay, setup OpenGL.
|
||||
gl.initContext();
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) override;
|
||||
|
||||
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
|
||||
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil) override;
|
||||
bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int backbufferdepth) override;
|
||||
void unSetMode() override;
|
||||
|
||||
void setActive(bool active) override;
|
||||
|
||||
@@ -588,6 +588,7 @@ GLenum OpenGL::getGLBufferType(BufferType type)
|
||||
case BUFFERTYPE_VERTEX: return GL_ARRAY_BUFFER;
|
||||
case BUFFERTYPE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||
case BUFFERTYPE_TEXEL: return GL_TEXTURE_BUFFER;
|
||||
case BUFFERTYPE_UNIFORM: return GL_UNIFORM_BUFFER;
|
||||
case BUFFERTYPE_MAX_ENUM: return GL_ZERO;
|
||||
}
|
||||
|
||||
|
||||
@@ -603,7 +603,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
context = (void *) SDL_Metal_GetLayer(metalView);
|
||||
#endif
|
||||
|
||||
graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil);
|
||||
graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.depth);
|
||||
}
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
|
||||
Reference in New Issue
Block a user