This commit is contained in:
Jack Andersen 2016-01-14 20:48:05 -10:00
commit 6c5e8f5fe8
21 changed files with 640 additions and 416 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "LogVisor"]
path = LogVisor
url = https://github.com/AxioDL/LogVisor.git
[submodule "glslang"]
path = glslang
url = https://github.com/AxioDL/glslang.git

View File

@ -16,10 +16,12 @@ include_directories(include ${LOG_VISOR_INCLUDE_DIR})
if(NOT GEKKO AND NOT CAFE)
list(APPEND PLAT_SRCS
lib/graphicsdev/GL.cpp
lib/graphicsdev/Vulkan.cpp
lib/graphicsdev/glew.c)
list(APPEND PLAT_HDRS
include/boo/graphicsdev/GL.hpp)
include/boo/graphicsdev/GL.hpp
include/boo/graphicsdev/Vulkan.hpp)
endif()
if(WIN32)
@ -130,11 +132,16 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleCl
set_source_files_properties(lib/graphicsdev/glew.c PROPERTIES COMPILE_FLAGS -Os)
endif()
add_subdirectory(glslang/glslang EXCLUDE_FROM_ALL)
add_subdirectory(glslang/OGLCompilersDLL EXCLUDE_FROM_ALL)
add_subdirectory(glslang/SPIRV EXCLUDE_FROM_ALL)
list(APPEND _BOO_SYS_LIBS glslang OSDependent OGLCompiler SPIRV)
set(BOO_SYS_LIBS ${_BOO_SYS_LIBS} CACHE PATH "Boo System Libraries" FORCE)
set(BOO_SYS_DEFINES ${_BOO_SYS_DEFINES} CACHE PATH "Boo System Defines" FORCE)
add_definitions(${_BOO_SYS_DEFINES})
include_directories(include)
include_directories(include glslang)
add_library(Boo
lib/inputdev/CafeProPad.cpp include/boo/inputdev/CafeProPad.hpp

View File

@ -1,4 +1,4 @@
The AxioDL License
The MIT License
Copyright (c) 2015 libBoo Contributors
Original Authors: Jack Andersen and Phillip "Antidote" Stephens
@ -13,12 +13,6 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Redistributions of the Software may not embed or fetch 3rd-party promotions or
advertising ("adware") that are unrelated to the redistribution's content.
The Software may not be modified to connect to 3rd-party advertising sources
("ad-networks"). Self-promotions of distribution-extensions are permissible
(e.g. microtransactions).
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

1
glslang Submodule

@ -0,0 +1 @@
Subproject commit 0ea3c3f01acf58fefdfc7be3333022b8e84e1997

View File

@ -4,6 +4,7 @@
#include "System.hpp"
#include <memory>
#include <algorithm>
#include <cstring>
#undef min
#undef max
@ -35,7 +36,7 @@ struct SWindowRect
int location[2];
int size[2];
SWindowRect() {memset(this, 0, sizeof(SWindowRect));}
SWindowRect() {std::memset(this, 0, sizeof(SWindowRect));}
SWindowRect(int x, int y, int w, int h)
{
@ -240,7 +241,8 @@ enum class EMouseCursor
Pointer = 1,
HorizontalArrow = 2,
VerticalArrow = 3,
IBeam = 4
IBeam = 4,
Crosshairs = 5
};
enum class EClipboardType

View File

@ -1,5 +1,5 @@
#ifndef GDEV_GLES3_HPP
#define GDEV_GLES3_HPP
#ifndef GDEV_GL_HPP
#define GDEV_GL_HPP
#include "IGraphicsDataFactory.hpp"
#include "IGraphicsCommandQueue.hpp"
@ -63,4 +63,4 @@ public:
}
#endif // GDEV_GLES3_HPP
#endif // GDEV_GL_HPP

View File

@ -184,6 +184,7 @@ struct IGraphicsDataFactory
D3D11,
D3D12,
Metal,
Vulkan,
GX,
GX2
};
@ -292,6 +293,7 @@ public:
return *this;
}
~GraphicsDataToken() {doDestroy();}
operator bool() const {return m_factory && m_data;}
};
}

View File

@ -0,0 +1,82 @@
#ifndef GDEV_VULKAN_HPP
#define GDEV_VULKAN_HPP
#include "IGraphicsDataFactory.hpp"
#include "IGraphicsCommandQueue.hpp"
#include "boo/IGraphicsContext.hpp"
#include <vector>
#include <unordered_set>
#include <mutex>
namespace boo
{
class VulkanDataFactory : public IGraphicsDataFactory
{
friend struct VulkanCommandQueue;
IGraphicsContext* m_parent;
static ThreadLocalPtr<struct GLData> m_deferredData;
std::unordered_set<struct GLData*> m_committedData;
std::mutex m_committedMutex;
std::vector<int> m_texUnis;
void destroyData(IGraphicsData*);
void destroyAllData();
public:
VulkanDataFactory(IGraphicsContext* parent);
~VulkanDataFactory() {destroyAllData();}
Platform platform() const {return Platform::Vulkan;}
const SystemChar* platformName() const {return _S("Vulkan");}
IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
IGraphicsBufferS* newStaticBuffer(BufferUse use, std::unique_ptr<uint8_t[]>&& data, size_t stride, size_t count);
IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
std::unique_ptr<uint8_t[]>&& data, size_t sz);
ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height, size_t samples);
bool bindingNeedsVertexFormat() const {return true;}
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
std::vector<unsigned int>& vertBlobOut, std::vector<unsigned int>& fragBlobOut,
std::vector<unsigned int>& pipelineBlob,
size_t texCount, const char* texArrayName,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
size_t texCount, const char* texArrayName,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling)
{
std::vector<unsigned int> vertBlob;
std::vector<unsigned int> fragBlob;
std::vector<unsigned int> pipelineBlob;
return newShaderPipeline(vertSource, fragSource, vertBlob, fragBlob, pipelineBlob,
texCount, texArrayName, uniformBlockCount, uniformBlockNames,
srcFac, dstFac, depthTest, depthWrite, backfaceCulling);
}
IShaderDataBinding*
newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs);
void reset();
GraphicsDataToken commit();
};
}
#endif // GDEV_VULKAN_HPP

View File

@ -98,7 +98,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xmd.h>
#include <GL/glew.h>
#include "glew.h"
#ifdef __cplusplus
extern "C" {

View File

@ -66,16 +66,20 @@ class GLGraphicsBufferD : public IGraphicsBufferD
{
friend class GLDataFactory;
friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_bufs[3];
GLenum m_target;
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0;
int m_validMask = 0;
GLGraphicsBufferD(GLCommandQueue* q, BufferUse use, size_t sz)
: m_q(q), m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz)
GLGraphicsBufferD(BufferUse use, size_t sz)
: m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz)
{
glGenBuffers(3, m_bufs);
for (int i=0 ; i<3 ; ++i)
{
glBindBuffer(m_target, m_bufs[i]);
glBufferData(m_target, m_cpuSz, nullptr, GL_STREAM_DRAW);
}
}
void update(int b);
public:
@ -193,7 +197,6 @@ class GLTextureD : public ITextureD
{
friend class GLDataFactory;
friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_texs[3];
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0;
@ -201,7 +204,7 @@ class GLTextureD : public ITextureD
size_t m_width = 0;
size_t m_height = 0;
int m_validMask = 0;
GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt);
GLTextureD(size_t width, size_t height, TextureFormat fmt);
void update(int b);
public:
~GLTextureD();
@ -223,6 +226,7 @@ class GLTextureR : public ITextureR
size_t m_width = 0;
size_t m_height = 0;
size_t m_samples = 0;
GLenum m_target;
GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t samples);
public:
~GLTextureR();
@ -230,18 +234,29 @@ public:
void bind(size_t idx) const
{
glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glBindTexture(m_target, m_texs[0]);
}
void resize(size_t width, size_t height)
{
m_width = width;
m_height = height;
if (m_samples > 1)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA, width, height, GL_FALSE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
}
else
{
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
}
}
};
ITextureS*
@ -1142,7 +1157,7 @@ void GLGraphicsBufferD::update(int b)
if ((slot & m_validMask) == 0)
{
glBindBuffer(m_target, m_bufs[b]);
glBufferData(m_target, m_cpuSz, m_cpuBuf.get(), GL_DYNAMIC_DRAW);
glBufferSubData(m_target, 0, m_cpuSz, m_cpuBuf.get());
m_validMask |= slot;
}
}
@ -1173,18 +1188,17 @@ void GLGraphicsBufferD::bindUniform(size_t idx, int b)
IGraphicsBufferD*
GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{
GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue());
GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use, stride * count);
GLGraphicsBufferD* retval = new GLGraphicsBufferD(use, stride * count);
if (!m_deferredData.get())
m_deferredData.reset(new struct GLData());
m_deferredData->m_DBufs.emplace_back(retval);
return retval;
}
GLTextureD::GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height)
GLTextureD::GLTextureD(size_t width, size_t height, TextureFormat fmt)
: m_width(width), m_height(height)
{
int pxPitch;
int pxPitch = 4;
switch (fmt)
{
case TextureFormat::RGBA8:
@ -1250,8 +1264,7 @@ void GLTextureD::bind(size_t idx, int b)
ITextureD*
GLDataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{
GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue());
GLTextureD* retval = new GLTextureD(q, width, height, fmt);
GLTextureD* retval = new GLTextureD(width, height, fmt);
if (!m_deferredData.get())
m_deferredData.reset(new struct GLData());
m_deferredData->m_DTexs.emplace_back(retval);
@ -1262,10 +1275,22 @@ GLTextureR::GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t sa
: m_q(q), m_width(width), m_height(height), m_samples(samples)
{
glGenTextures(2, m_texs);
if (samples > 1)
{
m_target = GL_TEXTURE_2D_MULTISAMPLE;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, width, height, GL_FALSE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
}
else
{
m_target = GL_TEXTURE_2D;
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
}
m_q->addFBO(this);
}
GLTextureR::~GLTextureR() {glDeleteTextures(2, m_texs); m_q->delFBO(this);}

View File

@ -41,13 +41,13 @@ class MetalGraphicsBufferS : public IGraphicsBufferS
MetalGraphicsBufferS(BufferUse use, MetalContext* ctx, const void* data, size_t stride, size_t count)
: m_stride(stride), m_count(count), m_sz(stride * count)
{
m_buf = [ctx->m_dev.get() newBufferWithBytes:data length:m_sz options:MTL_STATIC];
m_buf = [ctx->m_dev newBufferWithBytes:data length:m_sz options:MTL_STATIC];
}
public:
size_t m_stride;
size_t m_count;
size_t m_sz;
NSPtr<id<MTLBuffer>> m_buf;
id<MTLBuffer> m_buf;
~MetalGraphicsBufferS() = default;
};
@ -62,15 +62,15 @@ class MetalGraphicsBufferD : public IGraphicsBufferD
: m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
{
m_cpuBuf.reset(new uint8_t[m_sz]);
m_bufs[0] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC];
m_bufs[1] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC];
m_bufs[0] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
m_bufs[1] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
}
void update(int b);
public:
size_t m_stride;
size_t m_count;
size_t m_sz;
NSPtr<id<MTLBuffer>> m_bufs[2];
id<MTLBuffer> m_bufs[2];
MetalGraphicsBufferD() = default;
void load(const void* data, size_t sz);
@ -95,20 +95,19 @@ class MetalTextureS : public ITextureS
default: break;
}
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool
{
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height
mipmapped:(mips>1)?YES:NO];
}
desc.get().usage = MTLTextureUsageShaderRead;
desc.get().mipmapLevelCount = mips;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
desc.usage = MTLTextureUsageShaderRead;
desc.mipmapLevelCount = mips;
m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<mips ; ++i)
{
[m_tex.get() replaceRegion:MTLRegionMake2D(0, 0, width, height)
[m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:i
withBytes:dataIt
bytesPerRow:width * ppitch];
@ -117,8 +116,9 @@ class MetalTextureS : public ITextureS
height /= 2;
}
}
}
public:
NSPtr<id<MTLTexture>> m_tex;
id<MTLTexture> m_tex;
~MetalTextureS() = default;
};
@ -139,21 +139,20 @@ class MetalTextureSA : public ITextureSA
default: break;
}
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool
{
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height
mipmapped:NO];
}
desc.get().textureType = MTLTextureType2DArray;
desc.get().arrayLength = layers;
desc.get().usage = MTLTextureUsageShaderRead;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
desc.textureType = MTLTextureType2DArray;
desc.arrayLength = layers;
desc.usage = MTLTextureUsageShaderRead;
m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<layers ; ++i)
{
[m_tex.get() replaceRegion:MTLRegionMake2D(0, 0, width, height)
[m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:0
slice:i
withBytes:dataIt
@ -162,8 +161,9 @@ class MetalTextureSA : public ITextureSA
dataIt += width * height * ppitch;
}
}
}
public:
NSPtr<id<MTLTexture>> m_tex;
id<MTLTexture> m_tex;
~MetalTextureSA() = default;
};
@ -199,20 +199,20 @@ class MetalTextureD : public ITextureD
m_cpuSz = width * height * m_pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool
{
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
width:width height:height
mipmapped:NO];
desc.usage = MTLTextureUsageShaderRead;
m_texs[0] = [ctx->m_dev newTextureWithDescriptor:desc];
m_texs[1] = [ctx->m_dev newTextureWithDescriptor:desc];
}
desc.get().usage = MTLTextureUsageShaderRead;
m_texs[0] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
m_texs[1] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
}
void update(int b);
public:
NSPtr<id<MTLTexture>> m_texs[2];
id<MTLTexture> m_texs[2];
~MetalTextureD() = default;
void load(const void* data, size_t sz);
@ -230,49 +230,49 @@ class MetalTextureR : public ITextureR
void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples)
{
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool
{
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:width height:height
mipmapped:NO];
m_passDesc = [MTLRenderPassDescriptor renderPassDescriptor];
}
desc.get().usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
desc.get().storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
desc.storageMode = MTLStorageModePrivate;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
if (samples > 1)
{
desc.get().textureType = MTLTextureType2DMultisample;
desc.get().sampleCount = samples;
m_msaaTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
desc.textureType = MTLTextureType2DMultisample;
desc.sampleCount = samples;
m_msaaTex = [ctx->m_dev newTextureWithDescriptor:desc];
desc.get().pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
m_passDesc.get().colorAttachments[0].texture = m_msaaTex.get();
m_passDesc.get().colorAttachments[0].resolveTexture = m_tex.get();
m_passDesc.get().colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.get().colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
m_passDesc.colorAttachments[0].texture = m_msaaTex;
m_passDesc.colorAttachments[0].resolveTexture = m_tex;
m_passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
m_passDesc.get().depthAttachment.texture = m_depthTex.get();
m_passDesc.get().depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.get().depthAttachment.storeAction = MTLStoreActionDontCare;
m_passDesc.depthAttachment.texture = m_depthTex;
m_passDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
}
else
{
desc.get().pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
m_passDesc.get().colorAttachments[0].texture = m_tex.get();
m_passDesc.get().colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.get().colorAttachments[0].storeAction = MTLStoreActionStore;
m_passDesc.colorAttachments[0].texture = m_tex;
m_passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_passDesc.get().depthAttachment.texture = m_depthTex.get();
m_passDesc.get().depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.get().depthAttachment.storeAction = MTLStoreActionDontCare;
m_passDesc.depthAttachment.texture = m_depthTex;
m_passDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
}
}
}
@ -284,10 +284,10 @@ class MetalTextureR : public ITextureR
}
public:
size_t samples() const {return m_samples;}
NSPtr<id<MTLTexture>> m_tex;
NSPtr<id<MTLTexture>> m_msaaTex;
NSPtr<id<MTLTexture>> m_depthTex;
NSPtr<MTLRenderPassDescriptor*> m_passDesc;
id<MTLTexture> m_tex;
id<MTLTexture> m_msaaTex;
id<MTLTexture> m_depthTex;
MTLRenderPassDescriptor* m_passDesc;
~MetalTextureR() = default;
void resize(MetalContext* ctx, size_t width, size_t height)
@ -301,7 +301,7 @@ public:
Setup(ctx, width, height, m_samples);
}
id<MTLTexture> getRenderColorRes() {if (m_samples > 1) return m_msaaTex.get(); return m_tex.get();}
id<MTLTexture> getRenderColorRes() {if (m_samples > 1) return m_msaaTex; return m_tex;}
};
static const size_t SEMANTIC_SIZE_TABLE[] =
@ -337,7 +337,7 @@ static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] =
struct MetalVertexFormat : IVertexFormat
{
size_t m_elementCount;
NSPtr<MTLVertexDescriptor*> m_vdesc;
MTLVertexDescriptor* m_vdesc;
MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
: m_elementCount(elementCount)
{
@ -354,12 +354,12 @@ struct MetalVertexFormat : IVertexFormat
}
m_vdesc = [MTLVertexDescriptor vertexDescriptor];
MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.get().layouts[0];
MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0];
layoutDesc.stride = stride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex;
layoutDesc.stepRate = 1;
layoutDesc = m_vdesc.get().layouts[1];
layoutDesc = m_vdesc.layouts[1];
layoutDesc.stride = instStride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance;
layoutDesc.stepRate = 1;
@ -369,7 +369,7 @@ struct MetalVertexFormat : IVertexFormat
for (size_t i=0 ; i<elementCount ; ++i)
{
const VertexElementDescriptor* elemin = &elements[i];
MTLVertexAttributeDescriptor* attrDesc = m_vdesc.get().attributes[i];
MTLVertexAttributeDescriptor* attrDesc = m_vdesc.attributes[i];
int semantic = int(elemin->semantic & VertexSemantic::SemanticMask);
if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None)
{
@ -415,40 +415,40 @@ class MetalShaderPipeline : public IShaderPipeline
if (backfaceCulling)
m_cullMode = MTLCullModeBack;
NSPtr<MTLRenderPipelineDescriptor*> desc = [MTLRenderPipelineDescriptor new];
desc.get().vertexFunction = vert;
desc.get().fragmentFunction = frag;
desc.get().vertexDescriptor = vtxFmt->m_vdesc.get();
desc.get().sampleCount = targetSamples;
desc.get().colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.get().colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero;
desc.get().colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
desc.get().colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
desc.get().depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
desc.get().inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
desc.vertexFunction = vert;
desc.fragmentFunction = frag;
desc.vertexDescriptor = vtxFmt->m_vdesc;
desc.sampleCount = targetSamples;
desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero;
desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
NSError* err = nullptr;
m_state = [ctx->m_dev.get() newRenderPipelineStateWithDescriptor:desc.get() error:&err];
m_state = [ctx->m_dev newRenderPipelineStateWithDescriptor:desc error:&err];
if (err)
Log.report(LogVisor::FatalError, "error making shader pipeline: %s",
[[err localizedDescription] UTF8String]);
NSPtr<MTLDepthStencilDescriptor*> dsDesc = [MTLDepthStencilDescriptor new];
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
if (depthTest)
dsDesc.get().depthCompareFunction = MTLCompareFunctionLessEqual;
dsDesc.get().depthWriteEnabled = depthWrite;
m_dsState = [ctx->m_dev.get() newDepthStencilStateWithDescriptor:dsDesc.get()];
dsDesc.depthCompareFunction = MTLCompareFunctionLessEqual;
dsDesc.depthWriteEnabled = depthWrite;
m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc];
}
public:
NSPtr<id<MTLRenderPipelineState>> m_state;
NSPtr<id<MTLDepthStencilState>> m_dsState;
id<MTLRenderPipelineState> m_state;
id<MTLDepthStencilState> m_dsState;
~MetalShaderPipeline() = default;
MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete;
MetalShaderPipeline(const MetalShaderPipeline&) = delete;
void bind(id<MTLRenderCommandEncoder> enc)
{
[enc setRenderPipelineState:m_state.get()];
[enc setDepthStencilState:m_dsState.get()];
[enc setRenderPipelineState:m_state];
[enc setDepthStencilState:m_dsState];
[enc setCullMode:m_cullMode];
}
};
@ -458,12 +458,12 @@ static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx)
if (buf->dynamic())
{
const MetalGraphicsBufferD* cbuf = static_cast<const MetalGraphicsBufferD*>(buf);
return cbuf->m_bufs[idx].get();
return cbuf->m_bufs[idx];
}
else
{
const MetalGraphicsBufferS* cbuf = static_cast<const MetalGraphicsBufferS*>(buf);
return cbuf->m_buf.get();
return cbuf->m_buf;
}
}
@ -474,22 +474,22 @@ static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx)
case TextureType::Dynamic:
{
const MetalTextureD* ctex = static_cast<const MetalTextureD*>(tex);
return ctex->m_texs[idx].get();
return ctex->m_texs[idx];
}
case TextureType::Static:
{
const MetalTextureS* ctex = static_cast<const MetalTextureS*>(tex);
return ctex->m_tex.get();
return ctex->m_tex;
}
case TextureType::StaticArray:
{
const MetalTextureSA* ctex = static_cast<const MetalTextureSA*>(tex);
return ctex->m_tex.get();
return ctex->m_tex;
}
case TextureType::Render:
{
const MetalTextureR* ctex = static_cast<const MetalTextureR*>(tex);
return ctex->m_tex.get();
return ctex->m_tex;
}
default: break;
}
@ -547,8 +547,8 @@ struct MetalCommandQueue : IGraphicsCommandQueue
MetalContext* m_ctx;
IWindow* m_parentWindow;
IGraphicsContext* m_parent;
NSPtr<id<MTLCommandBuffer>> m_cmdBuf;
NSPtr<id<MTLRenderCommandEncoder>> m_enc;
id<MTLCommandBuffer> m_cmdBuf;
id<MTLRenderCommandEncoder> m_enc;
bool m_running = true;
size_t m_fillBuf = 0;
@ -559,7 +559,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{
@autoreleasepool
{
m_cmdBuf = [ctx->m_q.get() commandBuffer];
m_cmdBuf = [ctx->m_q commandBuffer];
}
}
@ -567,7 +567,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{
m_running = false;
if (m_inProgress)
[m_cmdBuf.get() waitUntilCompleted];
[m_cmdBuf waitUntilCompleted];
}
~MetalCommandQueue()
@ -579,7 +579,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void setShaderDataBinding(IShaderDataBinding* binding)
{
MetalShaderDataBinding* cbind = static_cast<MetalShaderDataBinding*>(binding);
cbind->bind(m_enc.get(), m_fillBuf);
cbind->bind(m_enc, m_fillBuf);
m_boundData = cbind;
}
@ -587,10 +587,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void setRenderTarget(ITextureR* target)
{
MetalTextureR* ctarget = static_cast<MetalTextureR*>(target);
[m_enc.get() endEncoding];
[m_enc endEncoding];
@autoreleasepool
{
m_enc = [m_cmdBuf.get() renderCommandEncoderWithDescriptor:ctarget->m_passDesc.get()];
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_passDesc];
}
m_boundTarget = ctarget;
}
@ -599,7 +599,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{
MTLViewport vp = {double(rect.location[0]), double(rect.location[1]),
double(rect.size[0]), double(rect.size[1]), 0.0, 1.0};
[m_enc.get() setViewport:vp];
[m_enc setViewport:vp];
}
void setScissor(const SWindowRect& rect)
@ -609,7 +609,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
MTLScissorRect scissor = {NSUInteger(rect.location[0]),
NSUInteger(m_boundTarget->m_height - rect.location[1] - rect.size[1]),
NSUInteger(rect.size[0]), NSUInteger(rect.size[1])};
[m_enc.get() setScissorRect:scissor];
[m_enc setScissorRect:scissor];
}
}
@ -654,12 +654,12 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void draw(size_t start, size_t count)
{
[m_enc.get() drawPrimitives:m_primType vertexStart:start vertexCount:count];
[m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count];
}
void drawIndexed(size_t start, size_t count)
{
[m_enc.get() drawIndexedPrimitives:m_primType
[m_enc drawIndexedPrimitives:m_primType
indexCount:count
indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
@ -668,12 +668,12 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void drawInstances(size_t start, size_t count, size_t instCount)
{
[m_enc.get() drawPrimitives:m_primType vertexStart:start vertexCount:count instanceCount:instCount];
[m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count instanceCount:instCount];
}
void drawInstancesIndexed(size_t start, size_t count, size_t instCount)
{
[m_enc.get() drawIndexedPrimitives:m_primType
[m_enc drawIndexedPrimitives:m_primType
indexCount:count
indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
@ -707,13 +707,13 @@ struct MetalCommandQueue : IGraphicsCommandQueue
@autoreleasepool
{
[m_enc.get() endEncoding];
m_enc.reset();
[m_enc endEncoding];
m_enc = nullptr;
/* Abandon if in progress (renderer too slow) */
if (m_inProgress)
{
m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
m_cmdBuf = [m_ctx->m_q commandBuffer];
return;
}
@ -723,7 +723,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
for (const auto& resize : m_texResizes)
resize.first->resize(m_ctx, resize.second.first, resize.second.second);
m_texResizes.clear();
m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
m_cmdBuf = [m_ctx->m_q commandBuffer];
return;
}
@ -747,11 +747,11 @@ struct MetalCommandQueue : IGraphicsCommandQueue
if (drawable)
{
id<MTLTexture> dest = drawable.texture;
if (m_needsDisplay->m_tex.get().width == dest.width &&
m_needsDisplay->m_tex.get().height == dest.height)
if (m_needsDisplay->m_tex.width == dest.width &&
m_needsDisplay->m_tex.height == dest.height)
{
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf.get() blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_tex.get()
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_tex
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
@ -761,7 +761,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEnc endEncoding];
[m_cmdBuf.get() presentDrawable:drawable];
[m_cmdBuf presentDrawable:drawable];
}
}
}
@ -771,10 +771,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
m_drawBuf = m_fillBuf;
m_fillBuf ^= 1;
[m_cmdBuf.get() addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
[m_cmdBuf addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
m_inProgress = true;
[m_cmdBuf.get() commit];
m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
[m_cmdBuf commit];
m_cmdBuf = [m_ctx->m_q commandBuffer];
}
}
};
@ -784,7 +784,7 @@ void MetalGraphicsBufferD::update(int b)
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
id<MTLBuffer> res = m_bufs[b].get();
id<MTLBuffer> res = m_bufs[b];
memcpy(res.contents, m_cpuBuf.get(), m_sz);
m_validSlots |= slot;
}
@ -811,7 +811,7 @@ void MetalTextureD::update(int b)
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
id<MTLTexture> res = m_texs[b].get();
id<MTLTexture> res = m_texs[b];
[res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0 withBytes:m_cpuBuf.get() bytesPerRow:m_width*m_pxPitch];
m_validSlots |= slot;
@ -924,25 +924,25 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con
BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling)
{
NSPtr<MTLCompileOptions*> compOpts = [MTLCompileOptions new];
compOpts.get().languageVersion = MTLLanguageVersion1_1;
MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.languageVersion = MTLLanguageVersion1_1;
NSError* err = nullptr;
NSPtr<id<MTLLibrary>> vertShaderLib = [m_ctx->m_dev.get() newLibraryWithSource:@(vertSource)
options:compOpts.get()
id<MTLLibrary> vertShaderLib = [m_ctx->m_dev newLibraryWithSource:@(vertSource)
options:compOpts
error:&err];
if (err)
Log.report(LogVisor::FatalError, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]);
NSPtr<id<MTLFunction>> vertFunc = [vertShaderLib.get() newFunctionWithName:@"vmain"];
id<MTLFunction> vertFunc = [vertShaderLib newFunctionWithName:@"vmain"];
NSPtr<id<MTLLibrary>> fragShaderLib = [m_ctx->m_dev.get() newLibraryWithSource:@(fragSource)
options:compOpts.get()
id<MTLLibrary> fragShaderLib = [m_ctx->m_dev newLibraryWithSource:@(fragSource)
options:compOpts
error:&err];
if (err)
Log.report(LogVisor::FatalError, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]);
NSPtr<id<MTLFunction>> fragFunc = [fragShaderLib.get() newFunctionWithName:@"fmain"];
id<MTLFunction> fragFunc = [fragShaderLib newFunctionWithName:@"fmain"];
MetalShaderPipeline* retval = new MetalShaderPipeline(m_ctx, vertFunc.get(), fragFunc.get(),
MetalShaderPipeline* retval = new MetalShaderPipeline(m_ctx, vertFunc, fragFunc,
static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, depthTest, depthWrite, backfaceCulling);
if (!m_deferredData.get())

160
lib/graphicsdev/Vulkan.cpp Normal file
View File

@ -0,0 +1,160 @@
#include "boo/graphicsdev/Vulkan.hpp"
#include "boo/IGraphicsContext.hpp"
#include <vector>
#include <glslang/Public/ShaderLang.h>
#include <SPIRV/GlslangToSpv.h>
#include <LogVisor/LogVisor.hpp>
#undef min
#undef max
static const TBuiltInResource DefaultBuiltInResource =
{
32,
6,
32,
32,
64,
4096,
64,
32,
80,
32,
4096,
32,
128,
8,
16,
16,
15,
-8,
7,
8,
65535,
65535,
65535,
1024,
1024,
64,
1024,
16,
8,
8,
1,
60,
64,
64,
128,
128,
8,
8,
8,
0,
0,
0,
0,
0,
8,
8,
16,
256,
1024,
1024,
64,
128,
128,
16,
1024,
4096,
128,
128,
16,
1024,
120,
32,
64,
16,
0,
0,
0,
0,
8,
8,
1,
0,
0,
0,
0,
1,
1,
16384,
4,
64,
8,
8,
4,
{
1,
1,
1,
1,
1,
1,
1,
1,
1
}
};
namespace boo
{
static LogVisor::LogModule Log("boo::Vulkan");
IShaderPipeline* VulkanDataFactory::newShaderPipeline
(const char* vertSource, const char* fragSource,
std::vector<unsigned int>& vertBlobOut, std::vector<unsigned int>& fragBlobOut,
std::vector<unsigned int>& pipelineBlob,
size_t texCount, const char* texArrayName,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling)
{
if (vertBlobOut.empty() || fragBlobOut.empty())
{
glslang::TShader vs(EShLangVertex);
vs.setStrings(&vertSource, 1);
if (!vs.parse(&DefaultBuiltInResource, 110, true, EShMsgDefault))
{
Log.report(LogVisor::Error, "unable to compile vertex shader\n%s", vs.getInfoLog());
return nullptr;
}
glslang::TShader fs(EShLangFragment);
fs.setStrings(&fragSource, 1);
if (!fs.parse(&DefaultBuiltInResource, 110, true, EShMsgDefault))
{
Log.report(LogVisor::Error, "unable to compile fragment shader\n%s", fs.getInfoLog());
return nullptr;
}
glslang::TProgram prog;
prog.addShader(&vs);
prog.addShader(&fs);
if (!prog.link(EShMsgDefault))
{
Log.report(LogVisor::Error, "unable to link shader program\n%s", prog.getInfoLog());
return nullptr;
}
glslang::GlslangToSpv(*prog.getIntermediate(EShLangVertex), vertBlobOut);
glslang::GlslangToSpv(*prog.getIntermediate(EShLangFragment), fragBlobOut);
}
/* TODO: The actual Vulkan API stuff */
return nullptr;
}
}

View File

@ -16,7 +16,6 @@ namespace boo {class ApplicationCocoa;}
{
boo::ApplicationCocoa* m_app;
@public
NSPanel* aboutPanel;
}
- (id)initWithApp:(boo::ApplicationCocoa*)app;
@end
@ -69,36 +68,20 @@ public:
[[NSApplication sharedApplication] setDelegate:m_appDelegate];
/* App menu */
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]];
[rwkMenu addItemWithTitle:[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()]
action:@selector(aboutApp:)
keyEquivalent:@""];
NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen"
NSMenu* rootMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]];
NSMenuItem* fsItem = [appMenu addItemWithTitle:@"Toggle Full Screen"
action:@selector(toggleFs:)
keyEquivalent:@"f"];
[fsItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[rwkMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()]
[appMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quitItem = [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()]
action:@selector(quitApp:)
keyEquivalent:@"q"];
[quit_item setKeyEquivalentModifierMask:NSCommandKeyMask];
[[appMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]
action:nil keyEquivalent:@""] setSubmenu:rwkMenu];
[[NSApplication sharedApplication] setMainMenu:appMenu];
/* About panel */
NSRect aboutCr = NSMakeRect(0, 0, 300, 220);
aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr
styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask
backing:NSBackingStoreBuffered defer:YES];
[aboutPanel setTitle:[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()]];
NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr];
[aboutText setEditable:NO];
[aboutText setAlignment:NSCenterTextAlignment];
[aboutText setString:@"\nBoo Authors\n\nJackoalan\nAntidote\n"];
[aboutPanel setContentView:aboutText];
m_appDelegate->aboutPanel = aboutPanel;
[quitItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[[rootMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]
action:nil keyEquivalent:@""] setSubmenu:appMenu];
[[NSApplication sharedApplication] setMainMenu:rootMenu];
/* Determine which graphics API to use */
#if BOO_HAS_METAL
@ -106,7 +89,7 @@ public:
if (!arg.compare("--metal"))
{
m_metalCtx.m_dev = MTLCreateSystemDefaultDevice();
m_metalCtx.m_q = [m_metalCtx.m_dev.get() newCommandQueue];
m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue];
Log.report(LogVisor::Info, "using Metal renderer");
break;
}
@ -133,8 +116,10 @@ public:
m_clientReturn = m_callback.appMain(this);
/* Cleanup here */
std::vector<std::unique_ptr<IWindow>> toDelete;
toDelete.reserve(m_windows.size());
for (auto& window : m_windows)
delete window.second;
toDelete.emplace_back(window.second);
});
/* Already in Cocoa's event loop; return now */
@ -245,16 +230,6 @@ int ApplicationRun(IApplication::EPlatformType platform,
(void)sender;
return YES;
}
- (IBAction)aboutApp:(id)sender
{
(void)sender;
NSRect screenFrame = [[aboutPanel screen] frame];
CGFloat xPos = NSWidth(screenFrame)/2 - 300/2;
CGFloat yPos = NSHeight(screenFrame)/2 - 220/2;
NSRect aboutCr = NSMakeRect(xPos, yPos, 300, 220);
[aboutPanel setFrame:aboutCr display:NO];
[aboutPanel makeKeyAndOrderFront:self];
}
- (IBAction)toggleFs:(id)sender
{
(void)sender;

View File

@ -7,40 +7,6 @@
#endif
#include <Availability.h>
#include <utility>
template <class T>
class NSPtr
{
void* m_ptr = nullptr;
public:
NSPtr() = default;
~NSPtr()
{
T ptr = (__bridge_transfer T)m_ptr;
(void)ptr;
}
NSPtr(T&& recv) {*this = std::move(recv);}
NSPtr& operator=(T&& recv)
{
T old = (__bridge_transfer T)m_ptr;
(void)old;
m_ptr = (__bridge_retained void*)recv;
return *this;
}
NSPtr(const NSPtr& other) = delete;
NSPtr(NSPtr&& other) = default;
NSPtr& operator=(const NSPtr& other) = delete;
NSPtr& operator=(NSPtr&& other) = default;
operator bool() const {return m_ptr != 0;}
T get() const {return (__bridge T)m_ptr;}
void reset()
{
T old = (__bridge_transfer T)m_ptr;
(void)old;
m_ptr = nullptr;
}
};
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
#define BOO_HAS_METAL 1
@ -55,8 +21,8 @@ namespace boo
class IWindow;
struct MetalContext
{
NSPtr<id<MTLDevice>> m_dev;
NSPtr<id<MTLCommandQueue>> m_q;
id<MTLDevice> m_dev = nullptr;
id<MTLCommandQueue> m_q = nullptr;
struct Window
{
CAMetalLayer* m_metalLayer = nullptr;

View File

@ -1107,8 +1107,8 @@ static boo::ESpecialKey translateKeycode(short code)
- (void)reshape
{
boo::SWindowRect rect = {{int(self.frame.origin.x), int(self.frame.origin.y)},
{int(self.frame.size.width), int(self.frame.size.height)}};
boo::SWindowRect rect = {int(self.frame.origin.x), int(self.frame.origin.y),
int(self.frame.size.width), int(self.frame.size.height)};
if (resp->booContext->m_callback)
resp->booContext->m_callback->resized(rect);
[super reshape];
@ -1154,7 +1154,7 @@ static boo::ESpecialKey translateKeycode(short code)
- (CALayer*)makeBackingLayer
{
CAMetalLayer* layer = [CAMetalLayer new];
layer.device = m_ctx->m_dev.get();
layer.device = m_ctx->m_dev;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.framebufferOnly = NO;
return layer;
@ -1177,8 +1177,8 @@ static boo::ESpecialKey translateKeycode(short code)
- (void)reshapeHandler
{
boo::SWindowRect rect = {{int(self.frame.origin.x), int(self.frame.origin.y)},
{int(self.frame.size.width), int(self.frame.size.height)}};
boo::SWindowRect rect = {int(self.frame.origin.x), int(self.frame.origin.y),
int(self.frame.size.width), int(self.frame.size.height)};
boo::MetalContext::Window& w = m_ctx->m_windows[m_window];
std::unique_lock<std::mutex> lk(w.m_resizeLock);
if (resp->booContext->m_callback)
@ -1222,13 +1222,12 @@ class WindowCocoa : public IWindow
WindowCocoaInternal* m_nsWindow;
GraphicsContextCocoa* m_gfxCtx;
EMouseCursor m_cursor = EMouseCursor::None;
bool m_closed = false;
public:
WindowCocoa(const std::string& title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx)
{
dispatch_sync(dispatch_get_main_queue(),
^{
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title];
#if BOO_HAS_METAL
if (metalCtx->m_dev)
@ -1237,18 +1236,16 @@ public:
#endif
m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, lastGLCtx));
m_gfxCtx->initializeContext();
});
}
void _clearWindow()
{
/* Caller consumes reference on its own */
(void)(__bridge_retained void*)m_nsWindow;
m_nsWindow = nullptr;
m_closed = true;
}
~WindowCocoa()
{
if (!m_closed)
[m_nsWindow orderOut:nil];
delete m_gfxCtx;
APP->_deletedWindow(this);
@ -1309,6 +1306,9 @@ public:
case EMouseCursor::IBeam:
[[NSCursor IBeamCursor] set];
break;
case EMouseCursor::Crosshairs:
[[NSCursor crosshairCursor] set];
break;
default: break;
}
});
@ -1491,7 +1491,12 @@ public:
IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx)
{
return new WindowCocoa(title, lastGLCtx, metalCtx);
__block IWindow* window = nullptr;
dispatch_sync(dispatch_get_main_queue(),
^{
window = new WindowCocoa(title, lastGLCtx, metalCtx);
});
return window;
}
}
@ -1506,6 +1511,7 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
NSResizableWindowMask
backing:NSBackingStoreBuffered
defer:YES];
self.releasedWhenClosed = NO;
self.title = [NSString stringWithUTF8String:title.c_str()];
booWindow = bw;
return self;

View File

@ -97,6 +97,7 @@ public:
WIN32_CURSORS.m_hResize = LoadCursor(nullptr, IDC_SIZEWE);
WIN32_CURSORS.m_vResize = LoadCursor(nullptr, IDC_SIZENS);
WIN32_CURSORS.m_ibeam = LoadCursor(nullptr, IDC_IBEAM);
WIN32_CURSORS.m_crosshairs = LoadCursor(nullptr, IDC_CROSS);
WIN32_CURSORS.m_wait = LoadCursor(nullptr, IDC_WAIT);
HMODULE dxgilib = LoadLibraryW(L"dxgi.dll");

View File

@ -261,6 +261,7 @@ struct Win32Cursors
HCURSOR m_hResize;
HCURSOR m_vResize;
HCURSOR m_ibeam;
HCURSOR m_crosshairs;
HCURSOR m_wait;
};
namespace boo

View File

@ -698,6 +698,8 @@ class WindowWin32 : public IWindow
return WIN32_CURSORS.m_vResize;
case EMouseCursor::IBeam:
return WIN32_CURSORS.m_ibeam;
case EMouseCursor::Crosshairs:
return WIN32_CURSORS.m_crosshairs;
default: break;
}
return WIN32_CURSORS.m_arrow;

View File

@ -163,7 +163,7 @@ class ApplicationXlib final : public IApplication
std::unordered_map<Window, IWindow*> m_windows;
Display* m_xDisp = nullptr;
XIM m_xIM;
XIM m_xIM = nullptr;
XFontSet m_fontset;
XIMStyle m_bestStyle = 0;
int m_xDefaultScreen = 0;
@ -260,12 +260,8 @@ public:
if (XSetLocaleModifiers("") == nullptr)
Log.report(LogVisor::Warning, "Cannot set locale modifiers.");
if ((m_xIM = XOpenIM(m_xDisp, nullptr, nullptr, nullptr)) == nullptr)
if ((m_xIM = XOpenIM(m_xDisp, nullptr, nullptr, nullptr)))
{
Log.report(LogVisor::FatalError, "Couldn't open input method.");
return;
}
char** missing_charsets;
int num_missing_charsets = 0;
char* default_string;
@ -299,12 +295,14 @@ public:
return;
}
XFree(im_supported_styles);
}
m_xDefaultScreen = DefaultScreen(m_xDisp);
X_CURSORS.m_pointer = XCreateFontCursor(m_xDisp, XC_left_ptr);
X_CURSORS.m_hArrow = XCreateFontCursor(m_xDisp, XC_sb_h_double_arrow);
X_CURSORS.m_vArrow = XCreateFontCursor(m_xDisp, XC_sb_v_double_arrow);
X_CURSORS.m_ibeam = XCreateFontCursor(m_xDisp, XC_xterm);
X_CURSORS.m_crosshairs = XCreateFontCursor(m_xDisp, XC_cross);
X_CURSORS.m_wait = XCreateFontCursor(m_xDisp, XC_watch);
/* The xkb extension requests that the X server does not

View File

@ -495,11 +495,7 @@ public:
}
void present()
{
XLockDisplay(m_xDisp);
glXSwapBuffers(m_xDisp, m_glxWindow);
XUnlockDisplay(m_xDisp);
}
{ glXSwapBuffers(m_xDisp, m_glxWindow); }
};
@ -510,7 +506,7 @@ class WindowXlib : public IWindow
Colormap m_colormapId;
Window m_windowId;
XIMStyle m_bestStyle;
XIC m_xIC;
XIC m_xIC = nullptr;
GraphicsContextGLX m_gfxCtx;
uint32_t m_visualId;
@ -525,7 +521,7 @@ class WindowXlib : public IWindow
double m_vScrollLast = 0.0;
/* Cached window rectangle (to avoid repeated X queries) */
int m_wx, m_wy, m_ww, m_wh;
boo::SWindowRect m_wrect;
float m_pixelFactor;
bool m_inFs = false;
@ -547,6 +543,8 @@ class WindowXlib : public IWindow
return X_CURSORS.m_vArrow;
case EMouseCursor::IBeam:
return X_CURSORS.m_ibeam;
case EMouseCursor::Crosshairs:
return X_CURSORS.m_crosshairs;
default: break;
}
return X_CURSORS.m_pointer;
@ -603,6 +601,8 @@ public:
* Now go create an IC using the style we chose.
* Also set the window and fontset attributes now.
*/
if (xIM)
{
XPoint pt = {0,0};
XVaNestedList nlist;
m_xIC = XCreateIC(xIM, XNInputStyle, bestInputStyle,
@ -614,15 +614,11 @@ public:
nullptr),
nullptr);
XFree(nlist);
if (m_xIC == nullptr)
{
Log.report(LogVisor::FatalError, "Couldn't create input context.");
return;
}
long im_event_mask;
XGetICValues(m_xIC, XNFilterEvents, &im_event_mask, nullptr);
XSelectInput(display, m_windowId, swa.event_mask | im_event_mask);
XSetICFocus(m_xIC);
}
/* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */
XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)};
@ -904,6 +900,8 @@ public:
} m_clipData;
void claimKeyboardFocus(const int coord[2])
{
if (m_xIC)
{
XLockDisplay(m_xDisp);
if (!coord)
@ -912,14 +910,15 @@ public:
XUnlockDisplay(m_xDisp);
return;
}
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
XPoint pt = {short(coord[0]), short(m_wh - coord[1])};
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
XPoint pt = {short(coord[0]), short(m_wrect.size[1] - coord[1])};
XVaNestedList list = XVaCreateNestedList(0, XNSpotLocation, &pt, nullptr);
XSetICValues(m_xIC, XNPreeditAttributes, list, nullptr);
XFree(list);
XSetICFocus(m_xIC);
XUnlockDisplay(m_xDisp);
}
}
bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz)
{
@ -1108,39 +1107,40 @@ public:
SWindowCoord MakeButtonEventCoord(XEvent* event) const
{
int x = event->xbutton.x;
int y = m_wh-event->xbutton.y;
int y = m_wrect.size[1]-event->xbutton.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
{x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}
};
}
SWindowCoord MakeMotionEventCoord(XEvent* event) const
{
int x = event->xmotion.x;
int y = m_wh-event->xmotion.y;
int y = m_wrect.size[1]-event->xmotion.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
{x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}
};
}
SWindowCoord MakeCrossingEventCoord(XEvent* event) const
{
int x = event->xcrossing.x;
int y = m_wh-event->xcrossing.y;
int y = m_wrect.size[1]-event->xcrossing.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
{x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}
};
}
#if 0
/* This procedure sets the application's size constraints and returns
* the IM's preferred size for either the Preedit or Status areas,
* depending on the value of the name argument. The area argument is
@ -1167,6 +1167,7 @@ public:
XSetICValues(m_xIC, name, list, nullptr);
XFree(list);
}
#endif
void _incomingEvent(void* e)
{
@ -1194,16 +1195,14 @@ public:
int x, y;
XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xexpose.x, event->xexpose.y, &x, &y, &nw);
XGetWindowAttributes(m_xDisp, m_windowId, &wxa);
m_wx = x - wxa.x;
m_wy = y - wxa.y;
m_ww = event->xexpose.width;
m_wh = event->xexpose.height;
m_wrect.location[0] = x - wxa.x;
m_wrect.location[1] = y - wxa.y;
m_wrect.size[0] = event->xexpose.width;
m_wrect.size[1] = event->xexpose.height;
if (m_callback)
{
SWindowRect rect =
{ {m_wx, m_wy}, {m_ww, m_wh} };
XUnlockDisplay(m_xDisp);
m_callback->resized(rect);
m_callback->resized(m_wrect);
XLockDisplay(m_xDisp);
}
return;
@ -1215,17 +1214,13 @@ public:
int x, y;
XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xconfigure.x, event->xconfigure.y, &x, &y, &nw);
XGetWindowAttributes(m_xDisp, m_windowId, &wxa);
m_wx = x - wxa.x;
m_wy = y - wxa.y;
m_ww = event->xconfigure.width;
m_wh = event->xconfigure.height;
m_wrect.location[0] = x - wxa.x;
m_wrect.location[1] = y - wxa.y;
m_wrect.size[0] = event->xconfigure.width;
m_wrect.size[1] = event->xconfigure.height;
if (m_callback)
{
SWindowRect rect =
{ {m_wx, m_wy}, {m_ww, m_wh} };
m_callback->windowMoved(rect);
}
m_callback->windowMoved(m_wrect);
return;
}
case KeyPress:
@ -1236,14 +1231,17 @@ public:
EModifierKey modifierKey;
unsigned int state = event->xkey.state;
event->xkey.state &= ~ControlMask;
std::string utf8Frag = translateUTF8(&event->xkey, m_xIC);
ITextInputCallback* inputCb = m_callback->getTextInputCallback();
if (m_xIC)
{
std::string utf8Frag = translateUTF8(&event->xkey, m_xIC);
if (utf8Frag.size())
{
if (inputCb)
inputCb->insertText(utf8Frag);
return;
}
}
char charCode = translateKeysym(&event->xkey, specialKey, modifierKey);
EModifierKey modifierMask = translateModifiers(state);
if (charCode)
@ -1283,7 +1281,7 @@ public:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
EMouseButton button = translateButton(event->xbutton.button);
if (button != EMouseButton::None)
{
@ -1318,7 +1316,7 @@ public:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
EMouseButton button = translateButton(event->xbutton.button);
if (button != EMouseButton::None)
{
@ -1345,7 +1343,7 @@ public:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
m_callback->mouseMove(MakeMotionEventCoord(event));
}
return;
@ -1354,7 +1352,7 @@ public:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
m_callback->mouseEnter(MakeCrossingEventCoord(event));
}
return;
@ -1363,7 +1361,7 @@ public:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
m_callback->mouseLeave(MakeCrossingEventCoord(event));
}
return;
@ -1372,7 +1370,7 @@ public:
{
if (event->xgeneric.extension == XINPUT_OPCODE)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]);
switch (event->xgeneric.evtype)
{
case XI_Motion:
@ -1416,12 +1414,12 @@ public:
if (m_callback && didScroll)
{
int event_x = int(ev->event_x) >> 16;
int event_y = m_wh - (int(ev->event_y) >> 16);
int event_y = m_wrect.size[1] - (int(ev->event_y) >> 16);
SWindowCoord coord =
{
{event_x, event_y},
{int(event_x / m_pixelFactor), int(event_y / m_pixelFactor)},
{event_x / float(m_ww), event_y / float(m_wh)}
{event_x / float(m_wrect.size[0]), event_y / float(m_wrect.size[1])}
};
m_callback->scroll(coord, scrollDelta);
}

View File

@ -12,6 +12,7 @@ struct XlibCursors
Cursor m_hArrow;
Cursor m_vArrow;
Cursor m_ibeam;
Cursor m_crosshairs;
Cursor m_wait;
};
extern XlibCursors X_CURSORS;