mirror of https://github.com/AxioDL/boo.git
lots of initial GLES3 renderer implementation
This commit is contained in:
parent
3db5a7e211
commit
5435f01d20
|
@ -10,7 +10,10 @@ if(WIN32)
|
||||||
lib/win/ApplicationWin32.cpp
|
lib/win/ApplicationWin32.cpp
|
||||||
lib/win/WindowWin32.cpp
|
lib/win/WindowWin32.cpp
|
||||||
lib/inputdev/HIDListenerWinUSB.cpp
|
lib/inputdev/HIDListenerWinUSB.cpp
|
||||||
lib/inputdev/HIDDeviceWinUSB.cpp)
|
lib/inputdev/HIDDeviceWinUSB.cpp
|
||||||
|
lib/graphicsdev/D3D11.cpp
|
||||||
|
lib/graphicsdev/D3D12.cpp
|
||||||
|
lib/graphicsdev/GLES3.cpp)
|
||||||
list(APPEND _BOO_SYS_LIBS Winusb)
|
list(APPEND _BOO_SYS_LIBS Winusb)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
list(APPEND PLAT_SRCS
|
list(APPEND PLAT_SRCS
|
||||||
|
@ -18,7 +21,8 @@ elseif(APPLE)
|
||||||
lib/mac/WindowCocoa.mm
|
lib/mac/WindowCocoa.mm
|
||||||
lib/mac/GLViewCocoa.mm
|
lib/mac/GLViewCocoa.mm
|
||||||
lib/inputdev/HIDListenerIOKit.cpp
|
lib/inputdev/HIDListenerIOKit.cpp
|
||||||
lib/inputdev/HIDDeviceIOKit.cpp)
|
lib/inputdev/HIDDeviceIOKit.cpp
|
||||||
|
lib/graphicsdev/GLES3.cpp)
|
||||||
find_library(APPKIT_LIBRARY AppKit)
|
find_library(APPKIT_LIBRARY AppKit)
|
||||||
find_library(IOKIT_LIBRARY IOKit)
|
find_library(IOKIT_LIBRARY IOKit)
|
||||||
find_library(OPENGL_LIBRARY OpenGL)
|
find_library(OPENGL_LIBRARY OpenGL)
|
||||||
|
@ -30,9 +34,9 @@ else()
|
||||||
lib/x11/ApplicationWayland.hpp
|
lib/x11/ApplicationWayland.hpp
|
||||||
lib/x11/WindowXCB.cpp
|
lib/x11/WindowXCB.cpp
|
||||||
lib/x11/WindowWayland.cpp
|
lib/x11/WindowWayland.cpp
|
||||||
lib/x11/GraphicsContextWayland.cpp
|
|
||||||
lib/inputdev/HIDListenerUdev.cpp
|
lib/inputdev/HIDListenerUdev.cpp
|
||||||
lib/inputdev/HIDDeviceUdev.cpp)
|
lib/inputdev/HIDDeviceUdev.cpp
|
||||||
|
lib/graphicsdev/GLES3.cpp)
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
if(PKG_CONFIG_FOUND)
|
if(PKG_CONFIG_FOUND)
|
||||||
|
@ -94,6 +98,12 @@ add_library(Boo
|
||||||
include/boo/inputdev/IHIDListener.hpp
|
include/boo/inputdev/IHIDListener.hpp
|
||||||
lib/inputdev/IHIDDevice.hpp
|
lib/inputdev/IHIDDevice.hpp
|
||||||
include/boo/IGraphicsContext.hpp
|
include/boo/IGraphicsContext.hpp
|
||||||
|
include/boo/graphicsdev/IGraphicsDataFactory.hpp
|
||||||
|
include/boo/graphicsdev/IGraphicsCommandQueue.hpp
|
||||||
|
include/boo/graphicsdev/GLES3.hpp
|
||||||
|
include/boo/graphicsdev/D3D11.hpp
|
||||||
|
include/boo/graphicsdev/D3D12.hpp
|
||||||
|
include/boo/graphicsdev/Metal.hpp
|
||||||
include/boo/IWindow.hpp
|
include/boo/IWindow.hpp
|
||||||
include/boo/IApplication.hpp
|
include/boo/IApplication.hpp
|
||||||
include/boo/System.hpp
|
include/boo/System.hpp
|
||||||
|
|
|
@ -14,7 +14,7 @@ class IApplication;
|
||||||
|
|
||||||
struct IApplicationCallback
|
struct IApplicationCallback
|
||||||
{
|
{
|
||||||
virtual void appMain(IApplication*) {}
|
virtual int appMain(IApplication*) {}
|
||||||
virtual void appQuitting(IApplication*) {}
|
virtual void appQuitting(IApplication*) {}
|
||||||
virtual void appFilesOpen(IApplication*, const std::vector<SystemString>&) {}
|
virtual void appFilesOpen(IApplication*, const std::vector<SystemString>&) {}
|
||||||
};
|
};
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
virtual const std::vector<SystemString>& getArgs() const=0;
|
virtual const std::vector<SystemString>& getArgs() const=0;
|
||||||
|
|
||||||
/* Constructors/initializers for sub-objects */
|
/* Constructors/initializers for sub-objects */
|
||||||
virtual IWindow* newWindow(const SystemString& title)=0;
|
virtual std::unique_ptr<IWindow> newWindow(const SystemString& title)=0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#ifndef IGFXCONTEXT_HPP
|
#ifndef IGFXCONTEXT_HPP
|
||||||
#define IGFXCONTEXT_HPP
|
#define IGFXCONTEXT_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
struct IGraphicsCommandQueue;
|
||||||
|
struct IGraphicsDataFactory;
|
||||||
|
|
||||||
class IGraphicsContext
|
class IGraphicsContext
|
||||||
{
|
{
|
||||||
|
@ -42,6 +47,9 @@ public:
|
||||||
virtual void initializeContext()=0;
|
virtual void initializeContext()=0;
|
||||||
virtual void makeCurrent()=0;
|
virtual void makeCurrent()=0;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<IGraphicsCommandQueue> createCommandQueue()=0;
|
||||||
|
virtual std::unique_ptr<IGraphicsDataFactory> createDataFactory()=0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ public:
|
||||||
virtual bool isFullscreen() const=0;
|
virtual bool isFullscreen() const=0;
|
||||||
virtual void setFullscreen(bool fs)=0;
|
virtual void setFullscreen(bool fs)=0;
|
||||||
|
|
||||||
virtual void waitForRetrace()=0;
|
virtual size_t waitForRetrace(size_t lastCount)=0;
|
||||||
|
|
||||||
virtual uintptr_t getPlatformHandle() const=0;
|
virtual uintptr_t getPlatformHandle() const=0;
|
||||||
virtual void _incomingEvent(void* event) {(void)event;}
|
virtual void _incomingEvent(void* event) {(void)event;}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef GDEV_D3D11_HPP
|
||||||
|
#define GDEV_D3D11_HPP
|
||||||
|
|
||||||
|
#include "IGraphicsDataFactory.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
class D3D11DataFactory : public IGraphicsDataFactory
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GDEV_D3D11_HPP
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef GDEV_D3D12_HPP
|
||||||
|
#define GDEV_D3D12_HPP
|
||||||
|
|
||||||
|
#include "IGraphicsDataFactory.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
class D3D12DataFactory : public IGraphicsDataFactory
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GDEV_D3D12_HPP
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef GDEV_GLES3_HPP
|
||||||
|
#define GDEV_GLES3_HPP
|
||||||
|
|
||||||
|
#include "IGraphicsDataFactory.hpp"
|
||||||
|
#include "IGraphicsCommandQueue.hpp"
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
class GLES3VertexArray
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
GLuint m_vao = 0;
|
||||||
|
bool initObjects();
|
||||||
|
void clearObjects();
|
||||||
|
GLES3VertexArray() = default;
|
||||||
|
public:
|
||||||
|
operator bool() const {return m_vao != 0;}
|
||||||
|
~GLES3VertexArray() {clearObjects();}
|
||||||
|
GLES3VertexArray& operator=(const GLES3VertexArray&) = delete;
|
||||||
|
GLES3VertexArray(const GLES3VertexArray&) = delete;
|
||||||
|
GLES3VertexArray& operator=(GLES3VertexArray&& other)
|
||||||
|
{
|
||||||
|
m_vao = other.m_vao;
|
||||||
|
other.m_vao = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
GLES3VertexArray(GLES3VertexArray&& other) {*this = std::move(other);}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLES3DataFactory : public IGraphicsDataFactory
|
||||||
|
{
|
||||||
|
std::unique_ptr<IGraphicsData> m_deferredData;
|
||||||
|
public:
|
||||||
|
GLES3DataFactory();
|
||||||
|
|
||||||
|
Platform platform() const {return PlatformOGLES3;}
|
||||||
|
const char* platformName() const {return "OpenGL ES 3.0";}
|
||||||
|
|
||||||
|
const IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t sz);
|
||||||
|
IGraphicsBufferD* newDynamicBuffer(BufferUse use);
|
||||||
|
|
||||||
|
GLES3VertexArray newVertexArray(size_t elementCount, const VertexElementDescriptor* elements);
|
||||||
|
|
||||||
|
const ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
|
||||||
|
const void* data, size_t sz);
|
||||||
|
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
|
||||||
|
|
||||||
|
const IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
|
||||||
|
BlendFactor srcFac, BlendFactor dstFac,
|
||||||
|
bool depthTest, bool depthWrite, bool backfaceCulling);
|
||||||
|
|
||||||
|
const IShaderDataBinding*
|
||||||
|
newShaderDataBinding(const IShaderPipeline* pipeline,
|
||||||
|
size_t bufCount, const IGraphicsBuffer** bufs,
|
||||||
|
size_t texCount, const ITexture** texs);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
std::unique_ptr<IGraphicsData> commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GDEV_GLES3_HPP
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef IGFXCOMMANDQUEUE_HPP
|
||||||
|
#define IGFXCOMMANDQUEUE_HPP
|
||||||
|
|
||||||
|
#include "IGraphicsDataFactory.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IGraphicsCommandQueue
|
||||||
|
{
|
||||||
|
virtual ~IGraphicsCommandQueue() {}
|
||||||
|
|
||||||
|
using Platform = IGraphicsDataFactory::Platform;
|
||||||
|
virtual Platform platform() const=0;
|
||||||
|
virtual const char* platformName() const=0;
|
||||||
|
|
||||||
|
virtual void setShaderDataBinding(const IShaderDataBinding* binding)=0;
|
||||||
|
virtual void setRenderTarget(const ITextureD* target)=0;
|
||||||
|
|
||||||
|
virtual void setClearColor(const float rgba[4])=0;
|
||||||
|
virtual void clearTarget(bool render=true, bool depth=true)=0;
|
||||||
|
|
||||||
|
enum Primitive
|
||||||
|
{
|
||||||
|
PrimitiveTriangles,
|
||||||
|
TrimitiveTriStrips
|
||||||
|
};
|
||||||
|
virtual void setDrawPrimitive(Primitive prim)=0;
|
||||||
|
virtual void draw(size_t start, size_t count)=0;
|
||||||
|
virtual void drawIndexed(size_t start, size_t count)=0;
|
||||||
|
virtual void drawInstances(size_t start, size_t count, size_t instCount)=0;
|
||||||
|
virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount)=0;
|
||||||
|
|
||||||
|
virtual void execute()=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IGFXCOMMANDQUEUE_HPP
|
|
@ -0,0 +1,158 @@
|
||||||
|
#ifndef IGFXDATAFACTORY_HPP
|
||||||
|
#define IGFXDATAFACTORY_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IGraphicsBuffer
|
||||||
|
{
|
||||||
|
bool dynamic() const {return m_dynamic;}
|
||||||
|
protected:
|
||||||
|
bool m_dynamic;
|
||||||
|
IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Static resource buffer for verts, indices, uniform constants */
|
||||||
|
struct IGraphicsBufferS : IGraphicsBuffer
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
IGraphicsBufferS() : IGraphicsBuffer(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Dynamic resource buffer for verts, indices, uniform constants */
|
||||||
|
struct IGraphicsBufferD : IGraphicsBuffer
|
||||||
|
{
|
||||||
|
virtual void load(const void* data, size_t sz)=0;
|
||||||
|
virtual void* map(size_t sz)=0;
|
||||||
|
virtual void unmap()=0;
|
||||||
|
protected:
|
||||||
|
IGraphicsBufferD() : IGraphicsBuffer(true) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ITexture
|
||||||
|
{
|
||||||
|
bool dynamic() const {return m_dynamic;}
|
||||||
|
protected:
|
||||||
|
bool m_dynamic;
|
||||||
|
ITexture(bool dynamic) : m_dynamic(dynamic) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Static resource buffer for textures */
|
||||||
|
struct ITextureS : ITexture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ITextureS() : ITexture(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Dynamic resource buffer for textures */
|
||||||
|
struct ITextureD : ITexture
|
||||||
|
{
|
||||||
|
virtual void load(const void* data, size_t sz)=0;
|
||||||
|
virtual void* map(size_t sz)=0;
|
||||||
|
virtual void unmap()=0;
|
||||||
|
protected:
|
||||||
|
ITextureD() : ITexture(true) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Opaque token for referencing a complete graphics pipeline state necessary
|
||||||
|
* to rasterize geometry (shaders and blending modes mainly) */
|
||||||
|
struct IShaderPipeline {};
|
||||||
|
|
||||||
|
/** Opaque token serving as indirection table for shader resources
|
||||||
|
* and IShaderPipeline reference. Each renderable surface-material holds one
|
||||||
|
* as a reference */
|
||||||
|
struct IShaderDataBinding {};
|
||||||
|
|
||||||
|
/** Opaque token for maintaining ownership of factory-created resources
|
||||||
|
* deletion of this token triggers mass-deallocation of the factory's
|
||||||
|
* resource batch. */
|
||||||
|
struct IGraphicsData
|
||||||
|
{
|
||||||
|
virtual ~IGraphicsData() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Factory object for creating batches of resources as an IGraphicsData token */
|
||||||
|
struct IGraphicsDataFactory
|
||||||
|
{
|
||||||
|
virtual ~IGraphicsDataFactory() {}
|
||||||
|
|
||||||
|
enum Platform
|
||||||
|
{
|
||||||
|
PlatformNull,
|
||||||
|
PlatformOGLES3,
|
||||||
|
PlatformD3D11,
|
||||||
|
PlatformD3D12,
|
||||||
|
PlatformMetal,
|
||||||
|
PlatformGX,
|
||||||
|
PlatformGX2
|
||||||
|
};
|
||||||
|
virtual Platform platform() const=0;
|
||||||
|
virtual const char* platformName() const=0;
|
||||||
|
|
||||||
|
enum BufferUse
|
||||||
|
{
|
||||||
|
BufferUseNull,
|
||||||
|
BufferUseVertex,
|
||||||
|
BufferUseIndex,
|
||||||
|
BufferUseUniform
|
||||||
|
};
|
||||||
|
virtual const IGraphicsBufferS*
|
||||||
|
newStaticBuffer(BufferUse use, const void* data, size_t sz)=0;
|
||||||
|
virtual IGraphicsBufferD*
|
||||||
|
newDynamicBuffer(BufferUse use)=0;
|
||||||
|
|
||||||
|
struct VertexElementDescriptor
|
||||||
|
{
|
||||||
|
const IGraphicsBuffer* vertBuffer = nullptr;
|
||||||
|
const IGraphicsBuffer* indexBuffer = nullptr;
|
||||||
|
enum VertexSemantic
|
||||||
|
{
|
||||||
|
VertexSemanticPosition,
|
||||||
|
VertexSemanticNormal,
|
||||||
|
VertexSemanticColor,
|
||||||
|
VertexSemanticUV,
|
||||||
|
VertexSemanticWeight
|
||||||
|
} semantic;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TextureFormat
|
||||||
|
{
|
||||||
|
TextureFormatRGBA8,
|
||||||
|
TextureFormatDXT1,
|
||||||
|
TextureFormatPVRTC4
|
||||||
|
};
|
||||||
|
virtual const ITextureS*
|
||||||
|
newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
|
||||||
|
const void* data, size_t sz)=0;
|
||||||
|
virtual ITextureD*
|
||||||
|
newDynamicTexture(size_t width, size_t height, TextureFormat fmt)=0;
|
||||||
|
|
||||||
|
enum BlendFactor
|
||||||
|
{
|
||||||
|
BlendFactorZero,
|
||||||
|
BlendFactorOne,
|
||||||
|
BlendFactorSrcColor,
|
||||||
|
BlendFactorInvSrcColor,
|
||||||
|
BlendFactorDstColor,
|
||||||
|
BlendFactorInvDstColor,
|
||||||
|
BlendFactorSrcAlpha,
|
||||||
|
BlendFactorInvSrcAlpha,
|
||||||
|
BlendFactorDstAlpha,
|
||||||
|
BlendFactorInvDstAlpha
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual const IShaderDataBinding*
|
||||||
|
newShaderDataBinding(const IShaderPipeline* pipeline,
|
||||||
|
size_t bufCount, const IGraphicsBuffer** bufs,
|
||||||
|
size_t texCount, const ITexture** texs)=0;
|
||||||
|
|
||||||
|
virtual void reset()=0;
|
||||||
|
virtual std::unique_ptr<IGraphicsData> commit()=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IGFXDATAFACTORY_HPP
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef GDEV_METAL_HPP
|
||||||
|
#define GDEV_METAL_HPP
|
||||||
|
|
||||||
|
#include "IGraphicsDataFactory.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
class MetalDataFactory : public IGraphicsDataFactory
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GDEV_METAL_HPP
|
|
@ -0,0 +1,653 @@
|
||||||
|
#include "boo/graphicsdev/GLES3.hpp"
|
||||||
|
#include "boo/IGraphicsContext.hpp"
|
||||||
|
#include <GLES3/gl3ext.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
struct GLES3Data : IGraphicsData
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<class GLES3ShaderPipeline>> m_SPs;
|
||||||
|
std::vector<std::unique_ptr<class GLES3GraphicsBufferS>> m_SBufs;
|
||||||
|
std::vector<std::unique_ptr<class GLES3GraphicsBufferD>> m_DBufs;
|
||||||
|
std::vector<std::unique_ptr<class GLES3TextureS>> m_STexs;
|
||||||
|
std::vector<std::unique_ptr<class GLES3TextureD>> m_DTexs;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum USE_TABLE[] =
|
||||||
|
{
|
||||||
|
GL_INVALID_ENUM,
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
GL_ELEMENT_ARRAY_BUFFER,
|
||||||
|
GL_UNIFORM_BUFFER
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLES3GraphicsBufferS : IGraphicsBufferS
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
GLuint m_buf;
|
||||||
|
GLenum m_target;
|
||||||
|
GLES3GraphicsBufferS(IGraphicsDataFactory::BufferUse use, const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
m_target = USE_TABLE[use];
|
||||||
|
glGenBuffers(1, &m_buf);
|
||||||
|
glBindBuffer(m_target, m_buf);
|
||||||
|
glBufferData(m_target, sz, data, GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
~GLES3GraphicsBufferS() {glDeleteBuffers(1, &m_buf);}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLES3GraphicsBufferD : IGraphicsBufferD
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
GLuint m_buf;
|
||||||
|
GLenum m_target;
|
||||||
|
void* m_mappedBuf = nullptr;
|
||||||
|
size_t m_mappedSize = 0;
|
||||||
|
GLES3GraphicsBufferD(IGraphicsDataFactory::BufferUse use)
|
||||||
|
{
|
||||||
|
m_target = USE_TABLE[use];
|
||||||
|
glGenBuffers(1, &m_buf);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
~GLES3GraphicsBufferD() {glDeleteBuffers(1, &m_buf);}
|
||||||
|
|
||||||
|
void load(const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
glBindBuffer(m_target, m_buf);
|
||||||
|
glBufferData(m_target, sz, data, GL_DYNAMIC_DRAW);
|
||||||
|
}
|
||||||
|
void* map(size_t sz)
|
||||||
|
{
|
||||||
|
if (m_mappedBuf)
|
||||||
|
free(m_mappedBuf);
|
||||||
|
m_mappedBuf = malloc(sz);
|
||||||
|
m_mappedSize = sz;
|
||||||
|
return m_mappedBuf;
|
||||||
|
}
|
||||||
|
void unmap()
|
||||||
|
{
|
||||||
|
glBindBuffer(m_target, m_buf);
|
||||||
|
glBufferData(m_target, m_mappedSize, m_mappedBuf, GL_DYNAMIC_DRAW);
|
||||||
|
free(m_mappedBuf);
|
||||||
|
m_mappedBuf = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const IGraphicsBufferS*
|
||||||
|
GLES3DataFactory::newStaticBuffer(BufferUse use, const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
GLES3GraphicsBufferS* retval = new GLES3GraphicsBufferS(use, data, sz);
|
||||||
|
static_cast<GLES3Data*>(m_deferredData.get())->m_SBufs.emplace_back(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
IGraphicsBufferD*
|
||||||
|
GLES3DataFactory::newDynamicBuffer(BufferUse use)
|
||||||
|
{
|
||||||
|
GLES3GraphicsBufferD* retval = new GLES3GraphicsBufferD(use);
|
||||||
|
static_cast<GLES3Data*>(m_deferredData.get())->m_DBufs.emplace_back(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GLES3TextureS : ITextureS
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
GLuint m_tex;
|
||||||
|
GLES3TextureS(size_t width, size_t height, size_t mips,
|
||||||
|
IGraphicsDataFactory::TextureFormat fmt,
|
||||||
|
const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
const uint8_t* dataIt = static_cast<const uint8_t*>(data);
|
||||||
|
glGenTextures(1, &m_tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tex);
|
||||||
|
if (fmt == IGraphicsDataFactory::TextureFormatRGBA8)
|
||||||
|
{
|
||||||
|
for (size_t i=0 ; i<mips ; ++i)
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataIt);
|
||||||
|
dataIt += width * height * 4;
|
||||||
|
width /= 2;
|
||||||
|
height /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
~GLES3TextureS() {glDeleteTextures(1, &m_tex);}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLES3TextureD : ITextureD
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
friend class GLES3CommandQueue;
|
||||||
|
GLuint m_tex;
|
||||||
|
GLuint m_fbo;
|
||||||
|
void* m_mappedBuf = nullptr;
|
||||||
|
size_t m_mappedSize = 0;
|
||||||
|
size_t m_width = 0;
|
||||||
|
size_t m_height = 0;
|
||||||
|
GLES3TextureD(size_t width, size_t height,
|
||||||
|
IGraphicsDataFactory::TextureFormat fmt)
|
||||||
|
{
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
glGenTextures(1, &m_tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
~GLES3TextureD() {glDeleteTextures(1, &m_tex);}
|
||||||
|
|
||||||
|
void load(const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
}
|
||||||
|
void* map(size_t sz)
|
||||||
|
{
|
||||||
|
if (m_mappedBuf)
|
||||||
|
free(m_mappedBuf);
|
||||||
|
m_mappedBuf = malloc(sz);
|
||||||
|
m_mappedSize = sz;
|
||||||
|
return m_mappedBuf;
|
||||||
|
}
|
||||||
|
void unmap()
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_mappedBuf);
|
||||||
|
free(m_mappedBuf);
|
||||||
|
m_mappedBuf = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ITextureS*
|
||||||
|
GLES3DataFactory::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
|
||||||
|
const void* data, size_t sz)
|
||||||
|
{
|
||||||
|
GLES3TextureS* retval = new GLES3TextureS(width, height, mips, fmt, data, sz);
|
||||||
|
static_cast<GLES3Data*>(m_deferredData.get())->m_STexs.emplace_back(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
ITextureD*
|
||||||
|
GLES3DataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
|
||||||
|
{
|
||||||
|
GLES3TextureD* retval = new GLES3TextureD(width, height, fmt);
|
||||||
|
static_cast<GLES3Data*>(m_deferredData.get())->m_DTexs.emplace_back(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GLES3ShaderPipeline : IShaderPipeline
|
||||||
|
{
|
||||||
|
friend class GLES3DataFactory;
|
||||||
|
GLuint m_vert = 0;
|
||||||
|
GLuint m_frag = 0;
|
||||||
|
GLuint m_prog = 0;
|
||||||
|
GLenum m_sfactor = GL_ONE;
|
||||||
|
GLenum m_dfactor = GL_ZERO;
|
||||||
|
bool initObjects()
|
||||||
|
{
|
||||||
|
m_vert = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
m_frag = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
m_prog = glCreateProgram();
|
||||||
|
if (!m_vert || !m_frag || !m_prog)
|
||||||
|
{
|
||||||
|
|
||||||
|
glDeleteShader(m_vert);
|
||||||
|
m_vert = 0;
|
||||||
|
glDeleteShader(m_frag);
|
||||||
|
m_frag = 0;
|
||||||
|
glDeleteProgram(m_prog);
|
||||||
|
m_prog = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glAttachShader(m_prog, m_vert);
|
||||||
|
glAttachShader(m_prog, m_frag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void clearObjects()
|
||||||
|
{
|
||||||
|
if (m_vert)
|
||||||
|
glDeleteShader(m_vert);
|
||||||
|
if (m_frag)
|
||||||
|
glDeleteShader(m_frag);
|
||||||
|
if (m_prog)
|
||||||
|
glDeleteProgram(m_prog);
|
||||||
|
}
|
||||||
|
GLES3ShaderPipeline() = default;
|
||||||
|
public:
|
||||||
|
operator bool() const {return m_prog != 0;}
|
||||||
|
~GLES3ShaderPipeline() {clearObjects();}
|
||||||
|
GLES3ShaderPipeline& operator=(const GLES3ShaderPipeline&) = delete;
|
||||||
|
GLES3ShaderPipeline(const GLES3ShaderPipeline&) = delete;
|
||||||
|
GLES3ShaderPipeline& operator=(GLES3ShaderPipeline&& other)
|
||||||
|
{
|
||||||
|
m_vert = other.m_vert;
|
||||||
|
other.m_vert = 0;
|
||||||
|
m_frag = other.m_frag;
|
||||||
|
other.m_frag = 0;
|
||||||
|
m_prog = other.m_prog;
|
||||||
|
other.m_prog = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
GLES3ShaderPipeline(GLES3ShaderPipeline&& other) {*this = std::move(other);}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool GLES3VertexArray::initObjects()
|
||||||
|
{
|
||||||
|
glGenVertexArrays(1, &m_vao);
|
||||||
|
if (!m_vao)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLES3VertexArray::clearObjects()
|
||||||
|
{
|
||||||
|
glDeleteVertexArrays(1, &m_vao);
|
||||||
|
m_vao = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GLint SEMANTIC_COUNT_TABLE[] =
|
||||||
|
{
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
2,
|
||||||
|
4
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t SEMANTIC_SIZE_TABLE[] =
|
||||||
|
{
|
||||||
|
12,
|
||||||
|
12,
|
||||||
|
4,
|
||||||
|
8,
|
||||||
|
16
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum SEMANTIC_TYPE_TABLE[] =
|
||||||
|
{
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_FLOAT
|
||||||
|
};
|
||||||
|
|
||||||
|
GLES3VertexArray GLES3DataFactory::newVertexArray
|
||||||
|
(size_t elementCount, const VertexElementDescriptor* elements)
|
||||||
|
{
|
||||||
|
GLES3VertexArray vertArray;
|
||||||
|
if (!vertArray.initObjects())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unable to create vertex array object\n");
|
||||||
|
return vertArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t stride = 0;
|
||||||
|
for (size_t i=0 ; i<elementCount ; ++i)
|
||||||
|
{
|
||||||
|
const VertexElementDescriptor* desc = &elements[i];
|
||||||
|
stride += SEMANTIC_SIZE_TABLE[desc->semantic];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
glBindVertexArray(vertArray.m_vao);
|
||||||
|
const IGraphicsBuffer* lastVBO = nullptr;
|
||||||
|
const IGraphicsBuffer* lastEBO = nullptr;
|
||||||
|
for (size_t i=0 ; i<elementCount ; ++i)
|
||||||
|
{
|
||||||
|
const VertexElementDescriptor* desc = &elements[i];
|
||||||
|
if (desc->vertBuffer != lastVBO)
|
||||||
|
{
|
||||||
|
lastVBO = desc->vertBuffer;
|
||||||
|
if (lastVBO->dynamic())
|
||||||
|
{
|
||||||
|
const GLES3GraphicsBufferD* vbo = static_cast<const GLES3GraphicsBufferD*>(lastVBO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo->m_buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const GLES3GraphicsBufferS* vbo = static_cast<const GLES3GraphicsBufferS*>(lastVBO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo->m_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (desc->indexBuffer != lastEBO)
|
||||||
|
{
|
||||||
|
lastEBO = desc->indexBuffer;
|
||||||
|
if (lastEBO->dynamic())
|
||||||
|
{
|
||||||
|
const GLES3GraphicsBufferD* ebo = static_cast<const GLES3GraphicsBufferD*>(lastEBO);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo->m_buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const GLES3GraphicsBufferS* ebo = static_cast<const GLES3GraphicsBufferS*>(lastEBO);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo->m_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[desc->semantic],
|
||||||
|
SEMANTIC_TYPE_TABLE[desc->semantic], GL_TRUE, stride, (void*)offset);
|
||||||
|
offset += SEMANTIC_SIZE_TABLE[desc->semantic];
|
||||||
|
}
|
||||||
|
|
||||||
|
return vertArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GLenum BLEND_FACTOR_TABLE[] =
|
||||||
|
{
|
||||||
|
GL_ZERO,
|
||||||
|
GL_ONE,
|
||||||
|
GL_SRC_COLOR,
|
||||||
|
GL_ONE_MINUS_SRC_COLOR,
|
||||||
|
GL_DST_COLOR,
|
||||||
|
GL_ONE_MINUS_DST_COLOR,
|
||||||
|
GL_SRC_ALPHA,
|
||||||
|
GL_ONE_MINUS_SRC_ALPHA,
|
||||||
|
GL_DST_ALPHA,
|
||||||
|
GL_ONE_MINUS_DST_ALPHA
|
||||||
|
};
|
||||||
|
|
||||||
|
const IShaderPipeline* GLES3DataFactory::newShaderPipeline
|
||||||
|
(const char* vertSource, const char* fragSource,
|
||||||
|
BlendFactor srcFac, BlendFactor dstFac,
|
||||||
|
bool depthTest, bool depthWrite, bool backfaceCulling)
|
||||||
|
{
|
||||||
|
GLES3ShaderPipeline shader;
|
||||||
|
if (!shader.initObjects())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unable to create shader objects\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
shader.m_sfactor = BLEND_FACTOR_TABLE[srcFac];
|
||||||
|
shader.m_dfactor = BLEND_FACTOR_TABLE[dstFac];
|
||||||
|
|
||||||
|
glShaderSource(shader.m_vert, 1, &vertSource, nullptr);
|
||||||
|
glCompileShader(shader.m_vert);
|
||||||
|
GLint status;
|
||||||
|
glGetShaderiv(shader.m_vert, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status != GL_TRUE)
|
||||||
|
{
|
||||||
|
GLint logLen;
|
||||||
|
glGetShaderiv(shader.m_vert, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetShaderInfoLog(shader.m_vert, logLen, nullptr, log);
|
||||||
|
fprintf(stderr, "unable to compile vert source\n%s\n%s\n", log, vertSource);
|
||||||
|
free(log);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(shader.m_frag, 1, &fragSource, nullptr);
|
||||||
|
glCompileShader(shader.m_frag);
|
||||||
|
glGetShaderiv(shader.m_frag, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status != GL_TRUE)
|
||||||
|
{
|
||||||
|
GLint logLen;
|
||||||
|
glGetShaderiv(shader.m_frag, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetShaderInfoLog(shader.m_frag, logLen, nullptr, log);
|
||||||
|
fprintf(stderr, "unable to compile frag source\n%s\n%s\n", log, fragSource);
|
||||||
|
free(log);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
glLinkProgram(shader.m_prog);
|
||||||
|
glGetProgramiv(shader.m_prog, GL_LINK_STATUS, &status);
|
||||||
|
if (status != GL_TRUE)
|
||||||
|
{
|
||||||
|
GLint logLen;
|
||||||
|
glGetProgramiv(shader.m_prog, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetProgramInfoLog(shader.m_prog, logLen, nullptr, log);
|
||||||
|
fprintf(stderr, "unable to link shader program\n%s\n", log);
|
||||||
|
free(log);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLES3ShaderPipeline* retval = new GLES3ShaderPipeline(std::move(shader));
|
||||||
|
static_cast<GLES3Data*>(m_deferredData.get())->m_SPs.emplace_back(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GLES3ShaderDataBinding : IShaderDataBinding
|
||||||
|
{
|
||||||
|
void bind() const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const IShaderDataBinding*
|
||||||
|
GLES3DataFactory::newShaderDataBinding(const IShaderPipeline* pipeline,
|
||||||
|
size_t bufCount, const IGraphicsBuffer** bufs,
|
||||||
|
size_t texCount, const ITexture** texs)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLES3DataFactory::GLES3DataFactory()
|
||||||
|
: m_deferredData(new struct GLES3Data()) {}
|
||||||
|
|
||||||
|
void GLES3DataFactory::reset()
|
||||||
|
{
|
||||||
|
m_deferredData.reset(new struct GLES3Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IGraphicsData> GLES3DataFactory::commit()
|
||||||
|
{
|
||||||
|
std::unique_ptr<IGraphicsData> retval(new struct GLES3Data());
|
||||||
|
m_deferredData.swap(retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GLES3CommandQueue : IGraphicsCommandQueue
|
||||||
|
{
|
||||||
|
Platform platform() const {return IGraphicsDataFactory::PlatformOGLES3;}
|
||||||
|
const char* platformName() const {return "OpenGL ES 3.0";}
|
||||||
|
IGraphicsContext& m_parent;
|
||||||
|
|
||||||
|
struct Command
|
||||||
|
{
|
||||||
|
enum Op
|
||||||
|
{
|
||||||
|
OpSetShaderDataBinding,
|
||||||
|
OpSetRenderTarget,
|
||||||
|
OpSetClearColor,
|
||||||
|
OpClearTarget,
|
||||||
|
OpSetDrawPrimitive,
|
||||||
|
OpDraw,
|
||||||
|
OpDrawIndexed,
|
||||||
|
OpDrawInstances,
|
||||||
|
OpDrawInstancesIndexed
|
||||||
|
} m_op;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
const IShaderDataBinding* binding;
|
||||||
|
const ITextureD* target;
|
||||||
|
float rgba[4];
|
||||||
|
GLbitfield flags;
|
||||||
|
Primitive prim;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
size_t start;
|
||||||
|
size_t count;
|
||||||
|
size_t instCount;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Command(Op op) : m_op(op) {}
|
||||||
|
};
|
||||||
|
std::vector<Command> m_cmdBufs[3];
|
||||||
|
size_t m_fillBuf = 0;
|
||||||
|
size_t m_completeBuf = 0;
|
||||||
|
size_t m_drawBuf = 0;
|
||||||
|
bool m_running = true;
|
||||||
|
std::thread m_thr;
|
||||||
|
std::mutex m_mt;
|
||||||
|
std::condition_variable m_cv;
|
||||||
|
|
||||||
|
static void RenderingWorker(GLES3CommandQueue* self)
|
||||||
|
{
|
||||||
|
self->m_parent.makeCurrent();
|
||||||
|
while (self->m_running)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(self->m_mt);
|
||||||
|
self->m_cv.wait(lk);
|
||||||
|
if (!self->m_running)
|
||||||
|
break;
|
||||||
|
self->m_drawBuf = self->m_completeBuf;
|
||||||
|
}
|
||||||
|
std::vector<Command>& cmds = self->m_cmdBufs[self->m_drawBuf];
|
||||||
|
GLenum prim = GL_TRIANGLES;
|
||||||
|
for (const Command& cmd : cmds)
|
||||||
|
{
|
||||||
|
switch (cmd.m_op)
|
||||||
|
{
|
||||||
|
case Command::OpSetShaderDataBinding:
|
||||||
|
static_cast<const GLES3ShaderDataBinding*>(cmd.binding)->bind();
|
||||||
|
break;
|
||||||
|
case Command::OpSetRenderTarget:
|
||||||
|
{
|
||||||
|
const GLES3TextureD* tex = static_cast<const GLES3TextureD*>(cmd.target);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_fbo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Command::OpSetClearColor:
|
||||||
|
glClearColor(cmd.rgba[0], cmd.rgba[1], cmd.rgba[2], cmd.rgba[3]);
|
||||||
|
break;
|
||||||
|
case Command::OpClearTarget:
|
||||||
|
glClear(cmd.flags);
|
||||||
|
break;
|
||||||
|
case Command::OpSetDrawPrimitive:
|
||||||
|
if (cmd.prim == PrimitiveTriangles)
|
||||||
|
prim = GL_TRIANGLES;
|
||||||
|
else if (cmd.prim == TrimitiveTriStrips)
|
||||||
|
prim = GL_TRIANGLE_STRIP;
|
||||||
|
break;
|
||||||
|
case Command::OpDraw:
|
||||||
|
glDrawArrays(prim, cmd.start, cmd.count);
|
||||||
|
break;
|
||||||
|
case Command::OpDrawIndexed:
|
||||||
|
glDrawElements(prim, cmd.count, GL_UNSIGNED_INT, (void*)cmd.start);
|
||||||
|
break;
|
||||||
|
case Command::OpDrawInstances:
|
||||||
|
glDrawArraysInstanced(prim, cmd.start, cmd.count, cmd.instCount);
|
||||||
|
break;
|
||||||
|
case Command::OpDrawInstancesIndexed:
|
||||||
|
glDrawElementsInstanced(prim, cmd.count, GL_UNSIGNED_INT, (void*)cmd.start, cmd.instCount);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmds.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLES3CommandQueue(IGraphicsContext& parent)
|
||||||
|
: m_parent(parent),
|
||||||
|
m_thr(RenderingWorker, this) {}
|
||||||
|
|
||||||
|
~GLES3CommandQueue()
|
||||||
|
{
|
||||||
|
m_running = false;
|
||||||
|
m_cv.notify_one();
|
||||||
|
m_thr.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShaderDataBinding(const IShaderDataBinding* binding)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpSetShaderDataBinding);
|
||||||
|
cmds.back().binding = binding;
|
||||||
|
}
|
||||||
|
void setRenderTarget(const ITextureD* target)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpSetRenderTarget);
|
||||||
|
cmds.back().target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setClearColor(const float rgba[4])
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpSetClearColor);
|
||||||
|
cmds.back().rgba[0] = rgba[0];
|
||||||
|
cmds.back().rgba[1] = rgba[1];
|
||||||
|
cmds.back().rgba[2] = rgba[2];
|
||||||
|
cmds.back().rgba[3] = rgba[3];
|
||||||
|
}
|
||||||
|
void clearTarget(bool render=true, bool depth=true)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpClearTarget);
|
||||||
|
cmds.back().flags = 0;
|
||||||
|
if (render)
|
||||||
|
cmds.back().flags |= GL_COLOR_BUFFER_BIT;
|
||||||
|
if (depth)
|
||||||
|
cmds.back().flags |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDrawPrimitive(Primitive prim)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpSetDrawPrimitive);
|
||||||
|
cmds.back().prim = prim;
|
||||||
|
}
|
||||||
|
void draw(size_t start, size_t count)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpDraw);
|
||||||
|
cmds.back().start = start;
|
||||||
|
cmds.back().count = count;
|
||||||
|
}
|
||||||
|
void drawIndexed(size_t start, size_t count)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpDrawIndexed);
|
||||||
|
cmds.back().start = start;
|
||||||
|
cmds.back().count = count;
|
||||||
|
}
|
||||||
|
void drawInstances(size_t start, size_t count, size_t instCount)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpDrawInstances);
|
||||||
|
cmds.back().start = start;
|
||||||
|
cmds.back().count = count;
|
||||||
|
cmds.back().instCount = instCount;
|
||||||
|
}
|
||||||
|
void drawInstancesIndexed(size_t start, size_t count, size_t instCount)
|
||||||
|
{
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::OpDrawInstancesIndexed);
|
||||||
|
cmds.back().start = start;
|
||||||
|
cmds.back().count = count;
|
||||||
|
cmds.back().instCount = instCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(m_mt);
|
||||||
|
m_completeBuf = m_fillBuf;
|
||||||
|
for (size_t i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
if (i == m_completeBuf || i == m_drawBuf)
|
||||||
|
continue;
|
||||||
|
m_fillBuf = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lk.unlock();
|
||||||
|
m_cv.notify_one();
|
||||||
|
m_cmdBufs[m_fillBuf].clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IGraphicsCommandQueue* _NewGLES3CommandQueue(IGraphicsContext& parent)
|
||||||
|
{
|
||||||
|
return new struct GLES3CommandQueue(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -71,9 +71,9 @@ public:
|
||||||
return m_args;
|
return m_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWindow* newWindow(const std::string& title)
|
std::unique_ptr<IWindow> newWindow(const std::string& title)
|
||||||
{
|
{
|
||||||
return _WindowWaylandNew(title);
|
return std::unique_ptr<IWindow>(_WindowWaylandNew(title));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
DBusConnection* RegisterDBus(const char* appName, bool& isFirst);
|
DBusConnection* RegisterDBus(const char* appName, bool& isFirst);
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
@ -253,56 +254,69 @@ public:
|
||||||
if (!m_xcbConn)
|
if (!m_xcbConn)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
xcb_generic_event_t* event;
|
/* Spawn client thread */
|
||||||
fd_set fds;
|
int clientReturn = 0;
|
||||||
FD_ZERO(&fds);
|
std::thread clientThread([&]()
|
||||||
FD_SET(m_xcbFd, &fds);
|
{clientReturn = m_callback.appMain(this);});
|
||||||
FD_SET(m_dbusFd, &fds);
|
|
||||||
select(m_maxFd+1, &fds, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (FD_ISSET(m_xcbFd, &fds))
|
/* Begin application event loop */
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
event = xcb_poll_for_event(m_xcbConn);
|
xcb_generic_event_t* event;
|
||||||
if (event)
|
fd_set fds;
|
||||||
{
|
FD_ZERO(&fds);
|
||||||
bool windowEvent;
|
FD_SET(m_xcbFd, &fds);
|
||||||
xcb_window_t evWindow = GetWindowOfEvent(event, windowEvent);
|
FD_SET(m_dbusFd, &fds);
|
||||||
//fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
|
select(m_maxFd+1, &fds, NULL, NULL, NULL);
|
||||||
if (windowEvent)
|
|
||||||
{
|
|
||||||
auto window = m_windows.find(evWindow);
|
|
||||||
if (window != m_windows.end())
|
|
||||||
window->second->_incomingEvent(event);
|
|
||||||
}
|
|
||||||
free(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(m_dbusFd, &fds))
|
if (FD_ISSET(m_xcbFd, &fds))
|
||||||
{
|
|
||||||
DBusMessage* msg;
|
|
||||||
dbus_connection_read_write(m_dbus, 0);
|
|
||||||
while ((msg = dbus_connection_pop_message(m_dbus)))
|
|
||||||
{
|
{
|
||||||
/* check if the message is a signal from the correct interface and with the correct name */
|
event = xcb_poll_for_event(m_xcbConn);
|
||||||
if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open"))
|
if (event)
|
||||||
{
|
{
|
||||||
/* read the parameters */
|
bool windowEvent;
|
||||||
std::vector<std::string> paths;
|
xcb_window_t evWindow = GetWindowOfEvent(event, windowEvent);
|
||||||
DBusMessageIter iter;
|
//fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
|
||||||
dbus_message_iter_init(msg, &iter);
|
if (windowEvent)
|
||||||
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
|
|
||||||
{
|
{
|
||||||
const char* argVal;
|
auto window = m_windows.find(evWindow);
|
||||||
dbus_message_iter_get_basic(&iter, &argVal);
|
if (window != m_windows.end())
|
||||||
paths.push_back(argVal);
|
window->second->_incomingEvent(event);
|
||||||
dbus_message_iter_next(&iter);
|
|
||||||
}
|
}
|
||||||
m_callback.appFilesOpen(this, paths);
|
free(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(m_dbusFd, &fds))
|
||||||
|
{
|
||||||
|
DBusMessage* msg;
|
||||||
|
dbus_connection_read_write(m_dbus, 0);
|
||||||
|
while ((msg = dbus_connection_pop_message(m_dbus)))
|
||||||
|
{
|
||||||
|
/* check if the message is a signal from the correct interface and with the correct name */
|
||||||
|
if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open"))
|
||||||
|
{
|
||||||
|
/* read the parameters */
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
DBusMessageIter iter;
|
||||||
|
dbus_message_iter_init(msg, &iter);
|
||||||
|
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
|
||||||
|
{
|
||||||
|
const char* argVal;
|
||||||
|
dbus_message_iter_get_basic(&iter, &argVal);
|
||||||
|
paths.push_back(argVal);
|
||||||
|
dbus_message_iter_next(&iter);
|
||||||
|
}
|
||||||
|
m_callback.appFilesOpen(this, paths);
|
||||||
|
}
|
||||||
|
dbus_message_unref(msg);
|
||||||
}
|
}
|
||||||
dbus_message_unref(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_callback.appQuitting(this);
|
||||||
|
clientThread.join();
|
||||||
|
return clientReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& getUniqueName() const
|
const std::string& getUniqueName() const
|
||||||
|
@ -325,11 +339,11 @@ public:
|
||||||
return m_args;
|
return m_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWindow* newWindow(const std::string& title)
|
std::unique_ptr<IWindow> newWindow(const std::string& title)
|
||||||
{
|
{
|
||||||
IWindow* newWindow = _WindowXCBNew(title, m_xcbConn);
|
IWindow* newWindow = _WindowXCBNew(title, m_xcbConn);
|
||||||
m_windows[(xcb_window_t)newWindow->getPlatformHandle()] = newWindow;
|
m_windows[(xcb_window_t)newWindow->getPlatformHandle()] = newWindow;
|
||||||
return newWindow;
|
return std::unique_ptr<IWindow>(newWindow);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
#include "boo/IGraphicsContext.hpp"
|
|
||||||
#include "boo/IWindow.hpp"
|
|
||||||
|
|
||||||
namespace boo
|
|
||||||
{
|
|
||||||
|
|
||||||
struct GraphicsContextWayland : IGraphicsContext
|
|
||||||
{
|
|
||||||
|
|
||||||
EGraphicsAPI m_api;
|
|
||||||
EPixelFormat m_pf;
|
|
||||||
IWindow* m_parentWindow;
|
|
||||||
|
|
||||||
public:
|
|
||||||
IWindowCallback* m_callback;
|
|
||||||
|
|
||||||
GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow)
|
|
||||||
: m_api(api),
|
|
||||||
m_pf(PF_RGBA8),
|
|
||||||
m_parentWindow(parentWindow)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~GraphicsContextWayland()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _setCallback(IWindowCallback* cb)
|
|
||||||
{
|
|
||||||
m_callback = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGraphicsAPI getAPI() const
|
|
||||||
{
|
|
||||||
return m_api;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPixelFormat getPixelFormat() const
|
|
||||||
{
|
|
||||||
return m_pf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPixelFormat(EPixelFormat pf)
|
|
||||||
{
|
|
||||||
if (pf > PF_RGBAF32_Z24)
|
|
||||||
return;
|
|
||||||
m_pf = pf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initializeContext()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeCurrent()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
IGraphicsContext* _GraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api,
|
|
||||||
IWindow* parentWindow)
|
|
||||||
{
|
|
||||||
return new GraphicsContextWayland(api, parentWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -11,8 +11,59 @@ namespace boo
|
||||||
extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI;
|
extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI;
|
||||||
extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI;
|
extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI;
|
||||||
|
|
||||||
IGraphicsContext* _GraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api,
|
struct GraphicsContextWayland : IGraphicsContext
|
||||||
IWindow* parentWindow);
|
{
|
||||||
|
|
||||||
|
EGraphicsAPI m_api;
|
||||||
|
EPixelFormat m_pf;
|
||||||
|
IWindow* m_parentWindow;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IWindowCallback* m_callback;
|
||||||
|
|
||||||
|
GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow)
|
||||||
|
: m_api(api),
|
||||||
|
m_pf(PF_RGBA8),
|
||||||
|
m_parentWindow(parentWindow)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~GraphicsContextWayland()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setCallback(IWindowCallback* cb)
|
||||||
|
{
|
||||||
|
m_callback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGraphicsAPI getAPI() const
|
||||||
|
{
|
||||||
|
return m_api;
|
||||||
|
}
|
||||||
|
|
||||||
|
EPixelFormat getPixelFormat() const
|
||||||
|
{
|
||||||
|
return m_pf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPixelFormat(EPixelFormat pf)
|
||||||
|
{
|
||||||
|
if (pf > PF_RGBAF32_Z24)
|
||||||
|
return;
|
||||||
|
m_pf = pf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeContext()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeCurrent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct WindowWayland : IWindow
|
struct WindowWayland : IWindow
|
||||||
{
|
{
|
||||||
|
@ -81,10 +132,11 @@ struct WindowWayland : IWindow
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitForRetrace()
|
size_t waitForRetrace(size_t count)
|
||||||
{
|
{
|
||||||
unsigned int sync;
|
unsigned int sync;
|
||||||
FglXWaitVideoSyncSGI(1, 0, &sync);
|
FglXWaitVideoSyncSGI(1, 0, &sync);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t getPlatformHandle() const
|
uintptr_t getPlatformHandle() const
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "boo/IWindow.hpp"
|
#include "boo/IWindow.hpp"
|
||||||
#include "boo/IGraphicsContext.hpp"
|
#include "boo/IGraphicsContext.hpp"
|
||||||
#include "boo/IApplication.hpp"
|
#include "boo/IApplication.hpp"
|
||||||
|
#include "boo/graphicsdev/GLES3.hpp"
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_event.h>
|
#include <xcb/xcb_event.h>
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
IGraphicsCommandQueue* _NewGLES3CommandQueue(IGraphicsContext& parent);
|
||||||
|
|
||||||
extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI;
|
extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI;
|
||||||
extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI;
|
extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI;
|
||||||
|
@ -293,6 +295,16 @@ public:
|
||||||
free(reply);
|
free(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IGraphicsCommandQueue> createCommandQueue()
|
||||||
|
{
|
||||||
|
return std::unique_ptr<IGraphicsCommandQueue>(_NewGLES3CommandQueue(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IGraphicsDataFactory> createDataFactory()
|
||||||
|
{
|
||||||
|
return std::unique_ptr<IGraphicsDataFactory>(new struct GLES3DataFactory());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WindowXCB : IWindow
|
struct WindowXCB : IWindow
|
||||||
|
@ -425,6 +437,7 @@ public:
|
||||||
void showWindow()
|
void showWindow()
|
||||||
{
|
{
|
||||||
xcb_map_window(m_xcbConn, m_windowId);
|
xcb_map_window(m_xcbConn, m_windowId);
|
||||||
|
m_gfxCtx.makeCurrent();
|
||||||
xcb_flush(m_xcbConn);
|
xcb_flush(m_xcbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,10 +543,11 @@ public:
|
||||||
(const char*)&fsEvent);
|
(const char*)&fsEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitForRetrace()
|
size_t waitForRetrace(size_t count)
|
||||||
{
|
{
|
||||||
unsigned int sync;
|
unsigned int sync;
|
||||||
FglXWaitVideoSyncSGI(1, 0, &sync);
|
FglXWaitVideoSyncSGI(1, 0, &sync);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t getPlatformHandle() const
|
uintptr_t getPlatformHandle() const
|
||||||
|
|
|
@ -169,19 +169,29 @@ struct CTestWindowCallback : IWindowCallback
|
||||||
|
|
||||||
struct TestApplicationCallback : IApplicationCallback
|
struct TestApplicationCallback : IApplicationCallback
|
||||||
{
|
{
|
||||||
IWindow* mainWindow = NULL;
|
std::unique_ptr<IWindow> mainWindow;
|
||||||
boo::TestDeviceFinder devFinder;
|
boo::TestDeviceFinder devFinder;
|
||||||
CTestWindowCallback windowCallback;
|
CTestWindowCallback windowCallback;
|
||||||
void appMain(IApplication* app)
|
bool running = true;
|
||||||
|
int appMain(IApplication* app)
|
||||||
{
|
{
|
||||||
mainWindow = app->newWindow(_S("YAY!"));
|
mainWindow = app->newWindow(_S("YAY!"));
|
||||||
mainWindow->setCallback(&windowCallback);
|
mainWindow->setCallback(&windowCallback);
|
||||||
mainWindow->showWindow();
|
mainWindow->showWindow();
|
||||||
devFinder.startScanning();
|
devFinder.startScanning();
|
||||||
|
|
||||||
|
size_t retraceCount = 0;
|
||||||
|
while (running)
|
||||||
|
{
|
||||||
|
retraceCount = mainWindow->waitForRetrace(retraceCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
void appQuitting(IApplication*)
|
void appQuitting(IApplication*)
|
||||||
{
|
{
|
||||||
delete mainWindow;
|
running = false;
|
||||||
}
|
}
|
||||||
void appFilesOpen(IApplication*, const std::vector<SystemString>& paths)
|
void appFilesOpen(IApplication*, const std::vector<SystemString>& paths)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue