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"] [submodule "LogVisor"]
path = LogVisor path = LogVisor
url = https://github.com/AxioDL/LogVisor.git url = https://github.com/AxioDL/LogVisor.git
[submodule "glslang"]
path = glslang
url = https://github.com/AxioDL/glslang.git

View File

@ -16,14 +16,16 @@ include_directories(include ${LOG_VISOR_INCLUDE_DIR})
if(NOT GEKKO AND NOT CAFE) if(NOT GEKKO AND NOT CAFE)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/graphicsdev/GL.cpp lib/graphicsdev/GL.cpp
lib/graphicsdev/Vulkan.cpp
lib/graphicsdev/glew.c) lib/graphicsdev/glew.c)
list(APPEND PLAT_HDRS list(APPEND PLAT_HDRS
include/boo/graphicsdev/GL.hpp) include/boo/graphicsdev/GL.hpp
include/boo/graphicsdev/Vulkan.hpp)
endif() endif()
if(WIN32) if(WIN32)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/win/ApplicationWin32.cpp lib/win/ApplicationWin32.cpp
lib/win/WindowWin32.cpp lib/win/WindowWin32.cpp
lib/win/Win32Common.hpp lib/win/Win32Common.hpp
@ -39,7 +41,7 @@ if(WIN32)
list(APPEND _BOO_SYS_LIBS Winusb opengl32 Setupapi Imm32) list(APPEND _BOO_SYS_LIBS Winusb opengl32 Setupapi Imm32)
elseif(APPLE) elseif(APPLE)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/mac/ApplicationCocoa.mm lib/mac/ApplicationCocoa.mm
lib/mac/WindowCocoa.mm lib/mac/WindowCocoa.mm
lib/mac/CocoaCommon.hpp lib/mac/CocoaCommon.hpp
@ -65,7 +67,7 @@ set_source_files_properties(lib/mac/ApplicationCocoa.mm
list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${METAL_LIBRARY} list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${METAL_LIBRARY}
${QUARTZCORE_LIBRARY} ${COREVIDEO_LIBRARY}) ${QUARTZCORE_LIBRARY} ${COREVIDEO_LIBRARY})
else(NOT GEKKO) else(NOT GEKKO)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/x11/XlibCommon.hpp lib/x11/XlibCommon.hpp
lib/x11/ApplicationUnix.cpp lib/x11/ApplicationUnix.cpp
lib/x11/ApplicationXlib.hpp lib/x11/ApplicationXlib.hpp
@ -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) set_source_files_properties(lib/graphicsdev/glew.c PROPERTIES COMPILE_FLAGS -Os)
endif() 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_LIBS ${_BOO_SYS_LIBS} CACHE PATH "Boo System Libraries" FORCE)
set(BOO_SYS_DEFINES ${_BOO_SYS_DEFINES} CACHE PATH "Boo System Defines" FORCE) set(BOO_SYS_DEFINES ${_BOO_SYS_DEFINES} CACHE PATH "Boo System Defines" FORCE)
add_definitions(${_BOO_SYS_DEFINES}) add_definitions(${_BOO_SYS_DEFINES})
include_directories(include) include_directories(include glslang)
add_library(Boo add_library(Boo
lib/inputdev/CafeProPad.cpp include/boo/inputdev/CafeProPad.hpp 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 Copyright (c) 2015 libBoo Contributors
Original Authors: Jack Andersen and Phillip "Antidote" Stephens 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 The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. 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 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 "System.hpp"
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include <cstring>
#undef min #undef min
#undef max #undef max
@ -35,7 +36,7 @@ struct SWindowRect
int location[2]; int location[2];
int size[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) SWindowRect(int x, int y, int w, int h)
{ {
@ -240,7 +241,8 @@ enum class EMouseCursor
Pointer = 1, Pointer = 1,
HorizontalArrow = 2, HorizontalArrow = 2,
VerticalArrow = 3, VerticalArrow = 3,
IBeam = 4 IBeam = 4,
Crosshairs = 5
}; };
enum class EClipboardType enum class EClipboardType

View File

@ -1,5 +1,5 @@
#ifndef GDEV_GLES3_HPP #ifndef GDEV_GL_HPP
#define GDEV_GLES3_HPP #define GDEV_GL_HPP
#include "IGraphicsDataFactory.hpp" #include "IGraphicsDataFactory.hpp"
#include "IGraphicsCommandQueue.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, D3D11,
D3D12, D3D12,
Metal, Metal,
Vulkan,
GX, GX,
GX2 GX2
}; };
@ -292,6 +293,7 @@ public:
return *this; return *this;
} }
~GraphicsDataToken() {doDestroy();} ~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/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/Xmd.h> #include <X11/Xmd.h>
#include <GL/glew.h> #include "glew.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

@ -66,16 +66,20 @@ class GLGraphicsBufferD : public IGraphicsBufferD
{ {
friend class GLDataFactory; friend class GLDataFactory;
friend struct GLCommandQueue; friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_bufs[3]; GLuint m_bufs[3];
GLenum m_target; GLenum m_target;
std::unique_ptr<uint8_t[]> m_cpuBuf; std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0; size_t m_cpuSz = 0;
int m_validMask = 0; int m_validMask = 0;
GLGraphicsBufferD(GLCommandQueue* q, BufferUse use, size_t sz) GLGraphicsBufferD(BufferUse use, size_t sz)
: m_q(q), m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz) : m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz)
{ {
glGenBuffers(3, m_bufs); 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); void update(int b);
public: public:
@ -193,7 +197,6 @@ class GLTextureD : public ITextureD
{ {
friend class GLDataFactory; friend class GLDataFactory;
friend struct GLCommandQueue; friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_texs[3]; GLuint m_texs[3];
std::unique_ptr<uint8_t[]> m_cpuBuf; std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0; size_t m_cpuSz = 0;
@ -201,7 +204,7 @@ class GLTextureD : public ITextureD
size_t m_width = 0; size_t m_width = 0;
size_t m_height = 0; size_t m_height = 0;
int m_validMask = 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); void update(int b);
public: public:
~GLTextureD(); ~GLTextureD();
@ -223,6 +226,7 @@ class GLTextureR : public ITextureR
size_t m_width = 0; size_t m_width = 0;
size_t m_height = 0; size_t m_height = 0;
size_t m_samples = 0; size_t m_samples = 0;
GLenum m_target;
GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t samples); GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t samples);
public: public:
~GLTextureR(); ~GLTextureR();
@ -230,17 +234,28 @@ public:
void bind(size_t idx) const void bind(size_t idx) const
{ {
glActiveTexture(GL_TEXTURE0 + idx); 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) void resize(size_t width, size_t height)
{ {
m_width = width; m_width = width;
m_height = height; m_height = height;
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); if (m_samples > 1)
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); 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);
}
} }
}; };
@ -1142,7 +1157,7 @@ void GLGraphicsBufferD::update(int b)
if ((slot & m_validMask) == 0) if ((slot & m_validMask) == 0)
{ {
glBindBuffer(m_target, m_bufs[b]); 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; m_validMask |= slot;
} }
} }
@ -1173,18 +1188,17 @@ void GLGraphicsBufferD::bindUniform(size_t idx, int b)
IGraphicsBufferD* IGraphicsBufferD*
GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count) GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{ {
GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue()); GLGraphicsBufferD* retval = new GLGraphicsBufferD(use, stride * count);
GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use, stride * count);
if (!m_deferredData.get()) if (!m_deferredData.get())
m_deferredData.reset(new struct GLData()); m_deferredData.reset(new struct GLData());
m_deferredData->m_DBufs.emplace_back(retval); m_deferredData->m_DBufs.emplace_back(retval);
return retval; return retval;
} }
GLTextureD::GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt) GLTextureD::GLTextureD(size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height) : m_width(width), m_height(height)
{ {
int pxPitch; int pxPitch = 4;
switch (fmt) switch (fmt)
{ {
case TextureFormat::RGBA8: case TextureFormat::RGBA8:
@ -1250,8 +1264,7 @@ void GLTextureD::bind(size_t idx, int b)
ITextureD* ITextureD*
GLDataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt) GLDataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{ {
GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue()); GLTextureD* retval = new GLTextureD(width, height, fmt);
GLTextureD* retval = new GLTextureD(q, width, height, fmt);
if (!m_deferredData.get()) if (!m_deferredData.get())
m_deferredData.reset(new struct GLData()); m_deferredData.reset(new struct GLData());
m_deferredData->m_DTexs.emplace_back(retval); 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) : m_q(q), m_width(width), m_height(height), m_samples(samples)
{ {
glGenTextures(2, m_texs); glGenTextures(2, m_texs);
glBindTexture(GL_TEXTURE_2D, m_texs[0]); if (samples > 1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); {
glBindTexture(GL_TEXTURE_2D, m_texs[1]); m_target = GL_TEXTURE_2D_MULTISAMPLE;
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); 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); m_q->addFBO(this);
} }
GLTextureR::~GLTextureR() {glDeleteTextures(2, m_texs); m_q->delFBO(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) 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_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: public:
size_t m_stride; size_t m_stride;
size_t m_count; size_t m_count;
size_t m_sz; size_t m_sz;
NSPtr<id<MTLBuffer>> m_buf; id<MTLBuffer> m_buf;
~MetalGraphicsBufferS() = default; ~MetalGraphicsBufferS() = default;
}; };
@ -62,15 +62,15 @@ class MetalGraphicsBufferD : public IGraphicsBufferD
: m_q(q), m_stride(stride), m_count(count), m_sz(stride * count) : m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
{ {
m_cpuBuf.reset(new uint8_t[m_sz]); m_cpuBuf.reset(new uint8_t[m_sz]);
m_bufs[0] = [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.get() newBufferWithLength:m_sz options:MTL_DYNAMIC]; m_bufs[1] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
} }
void update(int b); void update(int b);
public: public:
size_t m_stride; size_t m_stride;
size_t m_count; size_t m_count;
size_t m_sz; size_t m_sz;
NSPtr<id<MTLBuffer>> m_bufs[2]; id<MTLBuffer> m_bufs[2];
MetalGraphicsBufferD() = default; MetalGraphicsBufferD() = default;
void load(const void* data, size_t sz); void load(const void* data, size_t sz);
@ -95,30 +95,30 @@ class MetalTextureS : public ITextureS
default: break; default: break;
} }
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt MTLTextureDescriptor* desc =
width:width height:height [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
mipmapped:(mips>1)?YES:NO]; width:width height:height
} mipmapped:(mips>1)?YES:NO];
desc.get().usage = MTLTextureUsageShaderRead; desc.usage = MTLTextureUsageShaderRead;
desc.get().mipmapLevelCount = mips; desc.mipmapLevelCount = mips;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data); const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<mips ; ++i) 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 mipmapLevel:i
withBytes:dataIt withBytes:dataIt
bytesPerRow:width * ppitch]; bytesPerRow:width * ppitch];
dataIt += width * height * ppitch; dataIt += width * height * ppitch;
width /= 2; width /= 2;
height /= 2; height /= 2;
}
} }
} }
public: public:
NSPtr<id<MTLTexture>> m_tex; id<MTLTexture> m_tex;
~MetalTextureS() = default; ~MetalTextureS() = default;
}; };
@ -139,31 +139,31 @@ class MetalTextureSA : public ITextureSA
default: break; default: break;
} }
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt MTLTextureDescriptor* desc =
width:width height:height [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
mipmapped:NO]; width:width height:height
} mipmapped:NO];
desc.get().textureType = MTLTextureType2DArray; desc.textureType = MTLTextureType2DArray;
desc.get().arrayLength = layers; desc.arrayLength = layers;
desc.get().usage = MTLTextureUsageShaderRead; desc.usage = MTLTextureUsageShaderRead;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data); const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<layers ; ++i) 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 mipmapLevel:0
slice:i slice:i
withBytes:dataIt withBytes:dataIt
bytesPerRow:width * ppitch bytesPerRow:width * ppitch
bytesPerImage:width * height * ppitch]; bytesPerImage:width * height * ppitch];
dataIt += width * height * ppitch; dataIt += width * height * ppitch;
}
} }
} }
public: public:
NSPtr<id<MTLTexture>> m_tex; id<MTLTexture> m_tex;
~MetalTextureSA() = default; ~MetalTextureSA() = default;
}; };
@ -199,20 +199,20 @@ class MetalTextureD : public ITextureD
m_cpuSz = width * height * m_pxPitch; m_cpuSz = width * height * m_pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]); m_cpuBuf.reset(new uint8_t[m_cpuSz]);
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format MTLTextureDescriptor* desc =
width:width height:height [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
mipmapped:NO]; 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); void update(int b);
public: public:
NSPtr<id<MTLTexture>> m_texs[2]; id<MTLTexture> m_texs[2];
~MetalTextureD() = default; ~MetalTextureD() = default;
void load(const void* data, size_t sz); 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) void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples)
{ {
NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm MTLTextureDescriptor* desc =
width:width height:height [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
mipmapped:NO]; width:width height:height
mipmapped:NO];
m_passDesc = [MTLRenderPassDescriptor renderPassDescriptor]; m_passDesc = [MTLRenderPassDescriptor renderPassDescriptor];
} desc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
desc.get().usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; desc.storageMode = MTLStorageModePrivate;
desc.get().storageMode = MTLStorageModePrivate;
m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
if (samples > 1) if (samples > 1)
{ {
desc.get().textureType = MTLTextureType2DMultisample; desc.textureType = MTLTextureType2DMultisample;
desc.get().sampleCount = samples; desc.sampleCount = samples;
m_msaaTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_msaaTex = [ctx->m_dev newTextureWithDescriptor:desc];
desc.get().pixelFormat = MTLPixelFormatDepth32Float; desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
m_passDesc.get().colorAttachments[0].texture = m_msaaTex.get(); m_passDesc.colorAttachments[0].texture = m_msaaTex;
m_passDesc.get().colorAttachments[0].resolveTexture = m_tex.get(); m_passDesc.colorAttachments[0].resolveTexture = m_tex;
m_passDesc.get().colorAttachments[0].loadAction = MTLLoadActionClear; m_passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.get().colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve; m_passDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
m_passDesc.get().depthAttachment.texture = m_depthTex.get(); m_passDesc.depthAttachment.texture = m_depthTex;
m_passDesc.get().depthAttachment.loadAction = MTLLoadActionClear; m_passDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.get().depthAttachment.storeAction = MTLStoreActionDontCare; m_passDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
} }
else else
{ {
desc.get().pixelFormat = MTLPixelFormatDepth32Float; desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
m_passDesc.get().colorAttachments[0].texture = m_tex.get(); m_passDesc.colorAttachments[0].texture = m_tex;
m_passDesc.get().colorAttachments[0].loadAction = MTLLoadActionClear; m_passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_passDesc.get().colorAttachments[0].storeAction = MTLStoreActionStore; m_passDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_passDesc.get().depthAttachment.texture = m_depthTex.get(); m_passDesc.depthAttachment.texture = m_depthTex;
m_passDesc.get().depthAttachment.loadAction = MTLLoadActionClear; m_passDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_passDesc.get().depthAttachment.storeAction = MTLStoreActionDontCare; m_passDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
}
} }
} }
@ -284,10 +284,10 @@ class MetalTextureR : public ITextureR
} }
public: public:
size_t samples() const {return m_samples;} size_t samples() const {return m_samples;}
NSPtr<id<MTLTexture>> m_tex; id<MTLTexture> m_tex;
NSPtr<id<MTLTexture>> m_msaaTex; id<MTLTexture> m_msaaTex;
NSPtr<id<MTLTexture>> m_depthTex; id<MTLTexture> m_depthTex;
NSPtr<MTLRenderPassDescriptor*> m_passDesc; MTLRenderPassDescriptor* m_passDesc;
~MetalTextureR() = default; ~MetalTextureR() = default;
void resize(MetalContext* ctx, size_t width, size_t height) void resize(MetalContext* ctx, size_t width, size_t height)
@ -301,7 +301,7 @@ public:
Setup(ctx, width, height, m_samples); 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[] = static const size_t SEMANTIC_SIZE_TABLE[] =
@ -337,7 +337,7 @@ static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] =
struct MetalVertexFormat : IVertexFormat struct MetalVertexFormat : IVertexFormat
{ {
size_t m_elementCount; size_t m_elementCount;
NSPtr<MTLVertexDescriptor*> m_vdesc; MTLVertexDescriptor* m_vdesc;
MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements) MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
: m_elementCount(elementCount) : m_elementCount(elementCount)
{ {
@ -354,12 +354,12 @@ struct MetalVertexFormat : IVertexFormat
} }
m_vdesc = [MTLVertexDescriptor vertexDescriptor]; m_vdesc = [MTLVertexDescriptor vertexDescriptor];
MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.get().layouts[0]; MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0];
layoutDesc.stride = stride; layoutDesc.stride = stride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex; layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex;
layoutDesc.stepRate = 1; layoutDesc.stepRate = 1;
layoutDesc = m_vdesc.get().layouts[1]; layoutDesc = m_vdesc.layouts[1];
layoutDesc.stride = instStride; layoutDesc.stride = instStride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance; layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance;
layoutDesc.stepRate = 1; layoutDesc.stepRate = 1;
@ -369,7 +369,7 @@ struct MetalVertexFormat : IVertexFormat
for (size_t i=0 ; i<elementCount ; ++i) for (size_t i=0 ; i<elementCount ; ++i)
{ {
const VertexElementDescriptor* elemin = &elements[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); int semantic = int(elemin->semantic & VertexSemantic::SemanticMask);
if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None) if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None)
{ {
@ -415,40 +415,40 @@ class MetalShaderPipeline : public IShaderPipeline
if (backfaceCulling) if (backfaceCulling)
m_cullMode = MTLCullModeBack; m_cullMode = MTLCullModeBack;
NSPtr<MTLRenderPipelineDescriptor*> desc = [MTLRenderPipelineDescriptor new]; MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
desc.get().vertexFunction = vert; desc.vertexFunction = vert;
desc.get().fragmentFunction = frag; desc.fragmentFunction = frag;
desc.get().vertexDescriptor = vtxFmt->m_vdesc.get(); desc.vertexDescriptor = vtxFmt->m_vdesc;
desc.get().sampleCount = targetSamples; desc.sampleCount = targetSamples;
desc.get().colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.get().colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero; desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero;
desc.get().colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
desc.get().colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
desc.get().depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
desc.get().inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle; desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
NSError* err = nullptr; 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) if (err)
Log.report(LogVisor::FatalError, "error making shader pipeline: %s", Log.report(LogVisor::FatalError, "error making shader pipeline: %s",
[[err localizedDescription] UTF8String]); [[err localizedDescription] UTF8String]);
NSPtr<MTLDepthStencilDescriptor*> dsDesc = [MTLDepthStencilDescriptor new]; MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
if (depthTest) if (depthTest)
dsDesc.get().depthCompareFunction = MTLCompareFunctionLessEqual; dsDesc.depthCompareFunction = MTLCompareFunctionLessEqual;
dsDesc.get().depthWriteEnabled = depthWrite; dsDesc.depthWriteEnabled = depthWrite;
m_dsState = [ctx->m_dev.get() newDepthStencilStateWithDescriptor:dsDesc.get()]; m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc];
} }
public: public:
NSPtr<id<MTLRenderPipelineState>> m_state; id<MTLRenderPipelineState> m_state;
NSPtr<id<MTLDepthStencilState>> m_dsState; id<MTLDepthStencilState> m_dsState;
~MetalShaderPipeline() = default; ~MetalShaderPipeline() = default;
MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete; MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete;
MetalShaderPipeline(const MetalShaderPipeline&) = delete; MetalShaderPipeline(const MetalShaderPipeline&) = delete;
void bind(id<MTLRenderCommandEncoder> enc) void bind(id<MTLRenderCommandEncoder> enc)
{ {
[enc setRenderPipelineState:m_state.get()]; [enc setRenderPipelineState:m_state];
[enc setDepthStencilState:m_dsState.get()]; [enc setDepthStencilState:m_dsState];
[enc setCullMode:m_cullMode]; [enc setCullMode:m_cullMode];
} }
}; };
@ -458,12 +458,12 @@ static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx)
if (buf->dynamic()) if (buf->dynamic())
{ {
const MetalGraphicsBufferD* cbuf = static_cast<const MetalGraphicsBufferD*>(buf); const MetalGraphicsBufferD* cbuf = static_cast<const MetalGraphicsBufferD*>(buf);
return cbuf->m_bufs[idx].get(); return cbuf->m_bufs[idx];
} }
else else
{ {
const MetalGraphicsBufferS* cbuf = static_cast<const MetalGraphicsBufferS*>(buf); 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: case TextureType::Dynamic:
{ {
const MetalTextureD* ctex = static_cast<const MetalTextureD*>(tex); const MetalTextureD* ctex = static_cast<const MetalTextureD*>(tex);
return ctex->m_texs[idx].get(); return ctex->m_texs[idx];
} }
case TextureType::Static: case TextureType::Static:
{ {
const MetalTextureS* ctex = static_cast<const MetalTextureS*>(tex); const MetalTextureS* ctex = static_cast<const MetalTextureS*>(tex);
return ctex->m_tex.get(); return ctex->m_tex;
} }
case TextureType::StaticArray: case TextureType::StaticArray:
{ {
const MetalTextureSA* ctex = static_cast<const MetalTextureSA*>(tex); const MetalTextureSA* ctex = static_cast<const MetalTextureSA*>(tex);
return ctex->m_tex.get(); return ctex->m_tex;
} }
case TextureType::Render: case TextureType::Render:
{ {
const MetalTextureR* ctex = static_cast<const MetalTextureR*>(tex); const MetalTextureR* ctex = static_cast<const MetalTextureR*>(tex);
return ctex->m_tex.get(); return ctex->m_tex;
} }
default: break; default: break;
} }
@ -547,8 +547,8 @@ struct MetalCommandQueue : IGraphicsCommandQueue
MetalContext* m_ctx; MetalContext* m_ctx;
IWindow* m_parentWindow; IWindow* m_parentWindow;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
NSPtr<id<MTLCommandBuffer>> m_cmdBuf; id<MTLCommandBuffer> m_cmdBuf;
NSPtr<id<MTLRenderCommandEncoder>> m_enc; id<MTLRenderCommandEncoder> m_enc;
bool m_running = true; bool m_running = true;
size_t m_fillBuf = 0; size_t m_fillBuf = 0;
@ -559,7 +559,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{ {
@autoreleasepool @autoreleasepool
{ {
m_cmdBuf = [ctx->m_q.get() commandBuffer]; m_cmdBuf = [ctx->m_q commandBuffer];
} }
} }
@ -567,7 +567,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{ {
m_running = false; m_running = false;
if (m_inProgress) if (m_inProgress)
[m_cmdBuf.get() waitUntilCompleted]; [m_cmdBuf waitUntilCompleted];
} }
~MetalCommandQueue() ~MetalCommandQueue()
@ -579,7 +579,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void setShaderDataBinding(IShaderDataBinding* binding) void setShaderDataBinding(IShaderDataBinding* binding)
{ {
MetalShaderDataBinding* cbind = static_cast<MetalShaderDataBinding*>(binding); MetalShaderDataBinding* cbind = static_cast<MetalShaderDataBinding*>(binding);
cbind->bind(m_enc.get(), m_fillBuf); cbind->bind(m_enc, m_fillBuf);
m_boundData = cbind; m_boundData = cbind;
} }
@ -587,10 +587,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void setRenderTarget(ITextureR* target) void setRenderTarget(ITextureR* target)
{ {
MetalTextureR* ctarget = static_cast<MetalTextureR*>(target); MetalTextureR* ctarget = static_cast<MetalTextureR*>(target);
[m_enc.get() endEncoding]; [m_enc endEncoding];
@autoreleasepool @autoreleasepool
{ {
m_enc = [m_cmdBuf.get() renderCommandEncoderWithDescriptor:ctarget->m_passDesc.get()]; m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_passDesc];
} }
m_boundTarget = ctarget; m_boundTarget = ctarget;
} }
@ -599,7 +599,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{ {
MTLViewport vp = {double(rect.location[0]), double(rect.location[1]), MTLViewport vp = {double(rect.location[0]), double(rect.location[1]),
double(rect.size[0]), double(rect.size[1]), 0.0, 1.0}; 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) void setScissor(const SWindowRect& rect)
@ -609,7 +609,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
MTLScissorRect scissor = {NSUInteger(rect.location[0]), MTLScissorRect scissor = {NSUInteger(rect.location[0]),
NSUInteger(m_boundTarget->m_height - rect.location[1] - rect.size[1]), NSUInteger(m_boundTarget->m_height - rect.location[1] - rect.size[1]),
NSUInteger(rect.size[0]), NSUInteger(rect.size[1])}; NSUInteger(rect.size[0]), NSUInteger(rect.size[1])};
[m_enc.get() setScissorRect:scissor]; [m_enc setScissorRect:scissor];
} }
} }
@ -654,31 +654,31 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void draw(size_t start, size_t count) 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) void drawIndexed(size_t start, size_t count)
{ {
[m_enc.get() drawIndexedPrimitives:m_primType [m_enc drawIndexedPrimitives:m_primType
indexCount:count indexCount:count
indexType:MTLIndexTypeUInt32 indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf) indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
indexBufferOffset:start*4]; indexBufferOffset:start*4];
} }
void drawInstances(size_t start, size_t count, size_t instCount) 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) void drawInstancesIndexed(size_t start, size_t count, size_t instCount)
{ {
[m_enc.get() drawIndexedPrimitives:m_primType [m_enc drawIndexedPrimitives:m_primType
indexCount:count indexCount:count
indexType:MTLIndexTypeUInt32 indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf) indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
indexBufferOffset:start*4 indexBufferOffset:start*4
instanceCount:instCount]; instanceCount:instCount];
} }
MetalTextureR* m_needsDisplay = nullptr; MetalTextureR* m_needsDisplay = nullptr;
@ -707,13 +707,13 @@ struct MetalCommandQueue : IGraphicsCommandQueue
@autoreleasepool @autoreleasepool
{ {
[m_enc.get() endEncoding]; [m_enc endEncoding];
m_enc.reset(); m_enc = nullptr;
/* Abandon if in progress (renderer too slow) */ /* Abandon if in progress (renderer too slow) */
if (m_inProgress) if (m_inProgress)
{ {
m_cmdBuf = [m_ctx->m_q.get() commandBuffer]; m_cmdBuf = [m_ctx->m_q commandBuffer];
return; return;
} }
@ -723,7 +723,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
for (const auto& resize : m_texResizes) for (const auto& resize : m_texResizes)
resize.first->resize(m_ctx, resize.second.first, resize.second.second); resize.first->resize(m_ctx, resize.second.first, resize.second.second);
m_texResizes.clear(); m_texResizes.clear();
m_cmdBuf = [m_ctx->m_q.get() commandBuffer]; m_cmdBuf = [m_ctx->m_q commandBuffer];
return; return;
} }
@ -747,11 +747,11 @@ struct MetalCommandQueue : IGraphicsCommandQueue
if (drawable) if (drawable)
{ {
id<MTLTexture> dest = drawable.texture; id<MTLTexture> dest = drawable.texture;
if (m_needsDisplay->m_tex.get().width == dest.width && if (m_needsDisplay->m_tex.width == dest.width &&
m_needsDisplay->m_tex.get().height == dest.height) m_needsDisplay->m_tex.height == dest.height)
{ {
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf.get() blitCommandEncoder]; id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_tex.get() [blitEnc copyFromTexture:m_needsDisplay->m_tex
sourceSlice:0 sourceSlice:0
sourceLevel:0 sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0) sourceOrigin:MTLOriginMake(0, 0, 0)
@ -761,7 +761,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
destinationLevel:0 destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)]; destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEnc endEncoding]; [blitEnc endEncoding];
[m_cmdBuf.get() presentDrawable:drawable]; [m_cmdBuf presentDrawable:drawable];
} }
} }
} }
@ -771,10 +771,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
m_drawBuf = m_fillBuf; m_drawBuf = m_fillBuf;
m_fillBuf ^= 1; 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_inProgress = true;
[m_cmdBuf.get() commit]; [m_cmdBuf commit];
m_cmdBuf = [m_ctx->m_q.get() commandBuffer]; m_cmdBuf = [m_ctx->m_q commandBuffer];
} }
} }
}; };
@ -784,7 +784,7 @@ void MetalGraphicsBufferD::update(int b)
int slot = 1 << b; int slot = 1 << b;
if ((slot & m_validSlots) == 0) 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); memcpy(res.contents, m_cpuBuf.get(), m_sz);
m_validSlots |= slot; m_validSlots |= slot;
} }
@ -811,7 +811,7 @@ void MetalTextureD::update(int b)
int slot = 1 << b; int slot = 1 << b;
if ((slot & m_validSlots) == 0) 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) [res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0 withBytes:m_cpuBuf.get() bytesPerRow:m_width*m_pxPitch]; mipmapLevel:0 withBytes:m_cpuBuf.get() bytesPerRow:m_width*m_pxPitch];
m_validSlots |= slot; m_validSlots |= slot;
@ -924,25 +924,25 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con
BlendFactor srcFac, BlendFactor dstFac, BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling) bool depthTest, bool depthWrite, bool backfaceCulling)
{ {
NSPtr<MTLCompileOptions*> compOpts = [MTLCompileOptions new]; MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.get().languageVersion = MTLLanguageVersion1_1; compOpts.languageVersion = MTLLanguageVersion1_1;
NSError* err = nullptr; NSError* err = nullptr;
NSPtr<id<MTLLibrary>> vertShaderLib = [m_ctx->m_dev.get() newLibraryWithSource:@(vertSource) id<MTLLibrary> vertShaderLib = [m_ctx->m_dev newLibraryWithSource:@(vertSource)
options:compOpts.get() options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(LogVisor::FatalError, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]); 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) id<MTLLibrary> fragShaderLib = [m_ctx->m_dev newLibraryWithSource:@(fragSource)
options:compOpts.get() options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(LogVisor::FatalError, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]); 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, static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, depthTest, depthWrite, backfaceCulling); srcFac, dstFac, depthTest, depthWrite, backfaceCulling);
if (!m_deferredData.get()) 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; boo::ApplicationCocoa* m_app;
@public @public
NSPanel* aboutPanel;
} }
- (id)initWithApp:(boo::ApplicationCocoa*)app; - (id)initWithApp:(boo::ApplicationCocoa*)app;
@end @end
@ -69,36 +68,20 @@ public:
[[NSApplication sharedApplication] setDelegate:m_appDelegate]; [[NSApplication sharedApplication] setDelegate:m_appDelegate];
/* App menu */ /* App menu */
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"]; NSMenu* rootMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]]; NSMenu* appMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]];
[rwkMenu addItemWithTitle:[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] NSMenuItem* fsItem = [appMenu addItemWithTitle:@"Toggle Full Screen"
action:@selector(aboutApp:)
keyEquivalent:@""];
NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen"
action:@selector(toggleFs:) action:@selector(toggleFs:)
keyEquivalent:@"f"]; keyEquivalent:@"f"];
[fsItem setKeyEquivalentModifierMask:NSCommandKeyMask]; [fsItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[rwkMenu addItem:[NSMenuItem separatorItem]]; [appMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] NSMenuItem* quitItem = [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()]
action:@selector(quitApp:) action:@selector(quitApp:)
keyEquivalent:@"q"]; keyEquivalent:@"q"];
[quit_item setKeyEquivalentModifierMask:NSCommandKeyMask]; [quitItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[[appMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()] [[rootMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]
action:nil keyEquivalent:@""] setSubmenu:rwkMenu]; action:nil keyEquivalent:@""] setSubmenu:appMenu];
[[NSApplication sharedApplication] setMainMenu:appMenu]; [[NSApplication sharedApplication] setMainMenu:rootMenu];
/* 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;
/* Determine which graphics API to use */ /* Determine which graphics API to use */
#if BOO_HAS_METAL #if BOO_HAS_METAL
@ -106,7 +89,7 @@ public:
if (!arg.compare("--metal")) if (!arg.compare("--metal"))
{ {
m_metalCtx.m_dev = MTLCreateSystemDefaultDevice(); 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"); Log.report(LogVisor::Info, "using Metal renderer");
break; break;
} }
@ -133,8 +116,10 @@ public:
m_clientReturn = m_callback.appMain(this); m_clientReturn = m_callback.appMain(this);
/* Cleanup here */ /* Cleanup here */
std::vector<std::unique_ptr<IWindow>> toDelete;
toDelete.reserve(m_windows.size());
for (auto& window : m_windows) for (auto& window : m_windows)
delete window.second; toDelete.emplace_back(window.second);
}); });
/* Already in Cocoa's event loop; return now */ /* Already in Cocoa's event loop; return now */
@ -245,16 +230,6 @@ int ApplicationRun(IApplication::EPlatformType platform,
(void)sender; (void)sender;
return YES; 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 - (IBAction)toggleFs:(id)sender
{ {
(void)sender; (void)sender;

View File

@ -7,40 +7,6 @@
#endif #endif
#include <Availability.h> #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 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
#define BOO_HAS_METAL 1 #define BOO_HAS_METAL 1
@ -55,8 +21,8 @@ namespace boo
class IWindow; class IWindow;
struct MetalContext struct MetalContext
{ {
NSPtr<id<MTLDevice>> m_dev; id<MTLDevice> m_dev = nullptr;
NSPtr<id<MTLCommandQueue>> m_q; id<MTLCommandQueue> m_q = nullptr;
struct Window struct Window
{ {
CAMetalLayer* m_metalLayer = nullptr; CAMetalLayer* m_metalLayer = nullptr;

View File

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

View File

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

View File

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

View File

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

View File

@ -163,7 +163,7 @@ class ApplicationXlib final : public IApplication
std::unordered_map<Window, IWindow*> m_windows; std::unordered_map<Window, IWindow*> m_windows;
Display* m_xDisp = nullptr; Display* m_xDisp = nullptr;
XIM m_xIM; XIM m_xIM = nullptr;
XFontSet m_fontset; XFontSet m_fontset;
XIMStyle m_bestStyle = 0; XIMStyle m_bestStyle = 0;
int m_xDefaultScreen = 0; int m_xDefaultScreen = 0;
@ -260,51 +260,49 @@ public:
if (XSetLocaleModifiers("") == nullptr) if (XSetLocaleModifiers("") == nullptr)
Log.report(LogVisor::Warning, "Cannot set locale modifiers."); 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."); char** missing_charsets;
return; int num_missing_charsets = 0;
} char* default_string;
m_fontset = XCreateFontSet(m_xDisp,
"-adobe-helvetica-*-r-*-*-*-120-*-*-*-*-*-*,\
-misc-fixed-*-r-*-*-*-130-*-*-*-*-*-*",
&missing_charsets, &num_missing_charsets,
&default_string);
char** missing_charsets; /* figure out which styles the IM can support */
int num_missing_charsets = 0; XIMStyles* im_supported_styles;
char* default_string; XIMStyle app_supported_styles;
m_fontset = XCreateFontSet(m_xDisp, XGetIMValues(m_xIM, XNQueryInputStyle, &im_supported_styles, nullptr);
"-adobe-helvetica-*-r-*-*-*-120-*-*-*-*-*-*,\ /* set flags for the styles our application can support */
-misc-fixed-*-r-*-*-*-130-*-*-*-*-*-*", app_supported_styles = XIMPreeditNone | XIMPreeditNothing | XIMPreeditPosition;
&missing_charsets, &num_missing_charsets, app_supported_styles |= XIMStatusNone | XIMStatusNothing;
&default_string); /*
* now look at each of the IM supported styles, and
/* figure out which styles the IM can support */ * chose the "best" one that we can support.
XIMStyles* im_supported_styles; */
XIMStyle app_supported_styles; for (int i=0 ; i<im_supported_styles->count_styles ; ++i)
XGetIMValues(m_xIM, XNQueryInputStyle, &im_supported_styles, nullptr); {
/* set flags for the styles our application can support */ XIMStyle style = im_supported_styles->supported_styles[i];
app_supported_styles = XIMPreeditNone | XIMPreeditNothing | XIMPreeditPosition; if ((style & app_supported_styles) == style) /* if we can handle it */
app_supported_styles |= XIMStatusNone | XIMStatusNothing; m_bestStyle = ChooseBetterStyle(style, m_bestStyle);
/* }
* now look at each of the IM supported styles, and /* if we couldn't support any of them, print an error and exit */
* chose the "best" one that we can support. if (m_bestStyle == 0)
*/ {
for (int i=0 ; i<im_supported_styles->count_styles ; ++i) Log.report(LogVisor::FatalError, "interaction style not supported.");
{ return;
XIMStyle style = im_supported_styles->supported_styles[i]; }
if ((style & app_supported_styles) == style) /* if we can handle it */ XFree(im_supported_styles);
m_bestStyle = ChooseBetterStyle(style, m_bestStyle);
} }
/* if we couldn't support any of them, print an error and exit */
if (m_bestStyle == 0)
{
Log.report(LogVisor::FatalError, "interaction style not supported.");
return;
}
XFree(im_supported_styles);
m_xDefaultScreen = DefaultScreen(m_xDisp); m_xDefaultScreen = DefaultScreen(m_xDisp);
X_CURSORS.m_pointer = XCreateFontCursor(m_xDisp, XC_left_ptr); 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_hArrow = XCreateFontCursor(m_xDisp, XC_sb_h_double_arrow);
X_CURSORS.m_vArrow = XCreateFontCursor(m_xDisp, XC_sb_v_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_ibeam = XCreateFontCursor(m_xDisp, XC_xterm);
X_CURSORS.m_crosshairs = XCreateFontCursor(m_xDisp, XC_cross);
X_CURSORS.m_wait = XCreateFontCursor(m_xDisp, XC_watch); X_CURSORS.m_wait = XCreateFontCursor(m_xDisp, XC_watch);
/* The xkb extension requests that the X server does not /* The xkb extension requests that the X server does not

View File

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

View File

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