updated ebiten version from 2.7.9 to 2.9.9
This commit is contained in:
+118
-24
@@ -23,6 +23,8 @@ type Blend struct {
|
||||
BlendOperationAlpha BlendOperation
|
||||
}
|
||||
|
||||
// BlendFactor and BlendOperation must be synced with internal/graphicsdriver/playstation5/graphics_playstation5.h.
|
||||
|
||||
type BlendFactor byte
|
||||
|
||||
const (
|
||||
@@ -49,29 +51,121 @@ const (
|
||||
BlendOperationMax
|
||||
)
|
||||
|
||||
var BlendSourceOver = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorOneMinusSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
var (
|
||||
BlendSourceOver = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorOneMinusSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
var BlendClear = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorZero,
|
||||
BlendFactorSourceAlpha: BlendFactorZero,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
BlendClear = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorZero,
|
||||
BlendFactorSourceAlpha: BlendFactorZero,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
var BlendCopy = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
BlendCopy = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendDestination = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorZero,
|
||||
BlendFactorSourceAlpha: BlendFactorZero,
|
||||
BlendFactorDestinationRGB: BlendFactorOne,
|
||||
BlendFactorDestinationAlpha: BlendFactorOne,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendDestinationOver = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorOne,
|
||||
BlendFactorDestinationAlpha: BlendFactorOne,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendSourceIn = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendDestinationIn = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorZero,
|
||||
BlendFactorSourceAlpha: BlendFactorZero,
|
||||
BlendFactorDestinationRGB: BlendFactorSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendSourceOut = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendDestinationOut = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorZero,
|
||||
BlendFactorSourceAlpha: BlendFactorZero,
|
||||
BlendFactorDestinationRGB: BlendFactorOneMinusSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendSourceAtop = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorOneMinusSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendDestinationAtop = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendXor = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
|
||||
BlendFactorDestinationRGB: BlendFactorOneMinusSourceAlpha,
|
||||
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
|
||||
BlendLighter = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorOne,
|
||||
BlendFactorDestinationAlpha: BlendFactorOne,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
)
|
||||
|
||||
Generated
Vendored
+239
-63
@@ -16,94 +16,232 @@
|
||||
|
||||
package directx
|
||||
|
||||
// Some functions of ID3D12GraphicsCommandList has additional logics besides the original COM function call.
|
||||
// Some functions must be called with C++ directly for some reasons.
|
||||
// Then, instead of calling them by LazyProc.Call, we have to defer this call to the C++ side.
|
||||
// These functions are chosen based on the DirectX header file's implementation.
|
||||
//
|
||||
// These functions should be defined on the C++ side like this:
|
||||
//
|
||||
// extern "C" {
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearDepthStencilView(void* i, uintptr_t depthStencilView, int32_t clearFlags, float depth, uint8_t stencil, uint32_t numRects, void* pRects) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE{ depthStencilView }, static_cast<D3D12_CLEAR_FLAGS>(clearFlags), depth, stencil, numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearRenderTargetView(void* i, uintptr_t pRenderTargetView, void* colorRGBA, uint32_t numRects, void* pRects) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE{ pRenderTargetView }, static_cast<FLOAT*>(colorRGBA), numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
// }
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Close(void* i) {
|
||||
// auto r = static_cast<ID3D12GraphicsCommandList*>(i)->Close();
|
||||
// return uintptr_t(r);
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_CopyTextureRegion(void* i, void* pDst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, void* pSrc, void* pSrcBox) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->CopyTextureRegion(static_cast<D3D12_TEXTURE_COPY_LOCATION*>(pDst), dstX, dstY, dstZ, static_cast<D3D12_TEXTURE_COPY_LOCATION*>(pSrc), static_cast<D3D12_BOX*>(pSrcBox));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_DrawIndexedInstanced(void* i, uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetIndexBuffer(void* i, void* pView) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->IASetIndexBuffer(static_cast<D3D12_INDEX_BUFFER_VIEW*>(pView));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetPrimitiveTopology(void* i, int32_t primitiveTopology) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->IASetPrimitiveTopology(static_cast<D3D12_PRIMITIVE_TOPOLOGY>(primitiveTopology));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetVertexBuffers(void* i, uint32_t startSlot, uint32_t numViews, void* pViews) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->IASetVertexBuffers(startSlot, numViews, static_cast<D3D12_VERTEX_BUFFER_VIEW*>(pViews));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetRenderTargets(void* i, uint32_t numRenderTargetDescriptors, void* pRenderTargetDescriptors, int rtsSingleHandleToDescriptorRange, void* pDepthStencilDescriptor) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->OMSetRenderTargets(numRenderTargetDescriptors, static_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(pRenderTargetDescriptors), static_cast<BOOL>(rtsSingleHandleToDescriptorRange), static_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(pDepthStencilDescriptor));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetStencilRef(void* i, uint32_t stencilRef) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->OMSetStencilRef(stencilRef);
|
||||
// }
|
||||
// uint32_t Ebitengine_ID3D12GraphicsCommandList_Release(void* i) {
|
||||
// return static_cast<uint32_t>(static_cast<ID3D12GraphicsCommandList*>(i)->Release());
|
||||
// }
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Reset(void* i, void* pAllocator, void* pInitialState) {
|
||||
// auto r = static_cast<ID3D12GraphicsCommandList*>(i)->Reset(static_cast<ID3D12CommandAllocator*>(pAllocator), static_cast<ID3D12PipelineState*>(pInitialState));
|
||||
// return static_cast<uintptr_t>(r);
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ResourceBarrier(void* i, uint32_t numBarriers, void* pBarriers) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->ResourceBarrier(numBarriers, static_cast<D3D12_RESOURCE_BARRIER*>(pBarriers));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetViewports(void* i, uint32_t numViewports, void* pViewports) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->RSSetViewports(numViewports, static_cast<D3D12_VIEWPORT*>(pViewports));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetScissorRects(void* i, uint32_t numRects, void* pRects) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->RSSetScissorRects(numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetDescriptorHeaps(void* i, uint32_t numDescriptorHeaps, void* ppDescriptorHeaps) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->SetDescriptorHeaps(numDescriptorHeaps, static_cast<ID3D12DescriptorHeap**>(ppDescriptorHeaps));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(void* i, uint32_t rootParameterIndex, uint64_t baseDescriptorPtr) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->SetGraphicsRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptorPtr });
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootSignature(void* i, void* pRootSignature) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->SetGraphicsRootSignature(static_cast<ID3D12RootSignature*>(pRootSignature));
|
||||
// }
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetPipelineState(void* i, void* pPipelineState) {
|
||||
// static_cast<ID3D12GraphicsCommandList*>(i)->SetPipelineState(static_cast<ID3D12PipelineState*>(pPipelineState));
|
||||
// }
|
||||
// }
|
||||
/*
|
||||
extern "C" {
|
||||
|
||||
int32_t Ebitengine_D3D12_RESOURCE_STATE_PRESENT() {
|
||||
return static_cast<int32_t>(D3D12_RESOURCE_STATE_PRESENT);
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12CommandQueue_ExecuteCommandLists(void* i, uint32_t numCommandLists, void* ppCommandLists) {
|
||||
static_cast<ID3D12CommandQueue*>(i)->ExecuteCommandLists(numCommandLists, static_cast<ID3D12CommandList**>(ppCommandLists));
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12CommandQueue_PresentX(void* i, uint32_t planeCount, void* pPlaneParameters, void* pPresentParameters) {
|
||||
auto r = static_cast<ID3D12CommandQueue*>(i)->PresentX(planeCount, static_cast<D3D12XBOX_PRESENT_PLANE_PARAMETERS*>(pPlaneParameters), static_cast<D3D12XBOX_PRESENT_PARAMETERS*>(pPresentParameters));
|
||||
return static_cast<uintptr_t>(r);
|
||||
}
|
||||
|
||||
uint32_t Ebitengine_ID3D12CommandQueue_Release(void* i) {
|
||||
auto r = static_cast<ID3D12CommandQueue*>(i)->Release();
|
||||
return static_cast<uint32_t>(r);
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12CommandQueue_ResumeX(void* i) {
|
||||
auto r = static_cast<ID3D12CommandQueue*>(i)->ResumeX();
|
||||
return static_cast<uintptr_t>(r);
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12CommandQueue_Signal(void* i, void* pFence, uint64_t value) {
|
||||
auto r = static_cast<ID3D12CommandQueue*>(i)->Signal(static_cast<ID3D12Fence*>(pFence), value);
|
||||
return static_cast<uintptr_t>(r);
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12CommandQueue_SuspendX(void* i, uint32_t flags) {
|
||||
auto r = static_cast<ID3D12CommandQueue*>(i)->SuspendX(flags);
|
||||
return static_cast<uintptr_t>(r);
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_ClearDepthStencilView(void* i, uintptr_t depthStencilView, int32_t clearFlags, float depth, uint8_t stencil, uint32_t numRects, void* pRects) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE{ depthStencilView }, static_cast<D3D12_CLEAR_FLAGS>(clearFlags), depth, stencil, numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_ClearRenderTargetView(void* i, uintptr_t pRenderTargetView, void* colorRGBA, uint32_t numRects, void* pRects) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE{ pRenderTargetView }, static_cast<FLOAT*>(colorRGBA), numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12GraphicsCommandList_Close(void* i) {
|
||||
auto r = static_cast<ID3D12GraphicsCommandList*>(i)->Close();
|
||||
return uintptr_t(r);
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_CopyTextureRegion(void* i, void* pDst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, void* pSrc, void* pSrcBox) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->CopyTextureRegion(static_cast<D3D12_TEXTURE_COPY_LOCATION*>(pDst), dstX, dstY, dstZ, static_cast<D3D12_TEXTURE_COPY_LOCATION*>(pSrc), static_cast<D3D12_BOX*>(pSrcBox));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_DrawIndexedInstanced(void* i, uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_IASetIndexBuffer(void* i, void* pView) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->IASetIndexBuffer(static_cast<D3D12_INDEX_BUFFER_VIEW*>(pView));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_IASetPrimitiveTopology(void* i, int32_t primitiveTopology) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->IASetPrimitiveTopology(static_cast<D3D12_PRIMITIVE_TOPOLOGY>(primitiveTopology));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_IASetVertexBuffers(void* i, uint32_t startSlot, uint32_t numViews, void* pViews) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->IASetVertexBuffers(startSlot, numViews, static_cast<D3D12_VERTEX_BUFFER_VIEW*>(pViews));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_OMSetRenderTargets(void* i, uint32_t numRenderTargetDescriptors, void* pRenderTargetDescriptors, int rtsSingleHandleToDescriptorRange, void* pDepthStencilDescriptor) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->OMSetRenderTargets(numRenderTargetDescriptors, static_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(pRenderTargetDescriptors), static_cast<BOOL>(rtsSingleHandleToDescriptorRange), static_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(pDepthStencilDescriptor));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_OMSetStencilRef(void* i, uint32_t stencilRef) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->OMSetStencilRef(stencilRef);
|
||||
}
|
||||
|
||||
uint32_t Ebitengine_ID3D12GraphicsCommandList_Release(void* i) {
|
||||
return static_cast<uint32_t>(static_cast<ID3D12GraphicsCommandList*>(i)->Release());
|
||||
}
|
||||
|
||||
uintptr_t Ebitengine_ID3D12GraphicsCommandList_Reset(void* i, void* pAllocator, void* pInitialState) {
|
||||
auto r = static_cast<ID3D12GraphicsCommandList*>(i)->Reset(static_cast<ID3D12CommandAllocator*>(pAllocator), static_cast<ID3D12PipelineState*>(pInitialState));
|
||||
return static_cast<uintptr_t>(r);
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_ResourceBarrier(void* i, uint32_t numBarriers, void* pBarriers) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->ResourceBarrier(numBarriers, static_cast<D3D12_RESOURCE_BARRIER*>(pBarriers));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_RSSetViewports(void* i, uint32_t numViewports, void* pViewports) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->RSSetViewports(numViewports, static_cast<D3D12_VIEWPORT*>(pViewports));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_RSSetScissorRects(void* i, uint32_t numRects, void* pRects) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->RSSetScissorRects(numRects, static_cast<D3D12_RECT*>(pRects));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_SetDescriptorHeaps(void* i, uint32_t numDescriptorHeaps, void* ppDescriptorHeaps) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->SetDescriptorHeaps(numDescriptorHeaps, static_cast<ID3D12DescriptorHeap**>(ppDescriptorHeaps));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(void* i, uint32_t rootParameterIndex, uint64_t baseDescriptorPtr) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->SetGraphicsRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptorPtr });
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootSignature(void* i, void* pRootSignature) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->SetGraphicsRootSignature(static_cast<ID3D12RootSignature*>(pRootSignature));
|
||||
}
|
||||
|
||||
void Ebitengine_ID3D12GraphicsCommandList_SetPipelineState(void* i, void* pPipelineState) {
|
||||
static_cast<ID3D12GraphicsCommandList*>(i)->SetPipelineState(static_cast<ID3D12PipelineState*>(pPipelineState));
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// #include <stdint.h>
|
||||
//
|
||||
// #cgo noescape D3D12_RESOURCE_STATE_PRESENT
|
||||
// #cgo nocallback D3D12_RESOURCE_STATE_PRESENT
|
||||
// int32_t Ebitengine_D3D12_RESOURCE_STATE_PRESENT();
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_ExecuteCommandLists
|
||||
// #cgo nocallback ID3D12CommandQueue_ExecuteCommandLists
|
||||
// void Ebitengine_ID3D12CommandQueue_ExecuteCommandLists(void* i, uint32_t numCommandLists, void* ppCommandLists);
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_PresentX
|
||||
// #cgo nocallback ID3D12CommandQueue_PresentX
|
||||
// uintptr_t Ebitengine_ID3D12CommandQueue_PresentX(void* i, uint32_t planeCount, void* pPlaneParameters, void* pPresentParameters);
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_Release
|
||||
// #cgo nocallback ID3D12CommandQueue_Release
|
||||
// uint32_t Ebitengine_ID3D12CommandQueue_Release(void* i);
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_ResumeX
|
||||
// #cgo nocallback ID3D12CommandQueue_ResumeX
|
||||
// uintptr_t Ebitengine_ID3D12CommandQueue_ResumeX(void* i);
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_Signal
|
||||
// #cgo nocallback ID3D12CommandQueue_Signal
|
||||
// uintptr_t Ebitengine_ID3D12CommandQueue_Signal(void* i, void* pFence, uint64_t value);
|
||||
//
|
||||
// #cgo noescape ID3D12CommandQueue_SuspendX
|
||||
// #cgo nocallback ID3D12CommandQueue_SuspendX
|
||||
// uintptr_t Ebitengine_ID3D12CommandQueue_SuspendX(void* i, uint32_t flags);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_ClearDepthStencilView
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_ClearDepthStencilView
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearDepthStencilView(void* i, uintptr_t depthStencilView, int32_t clearFlags, float depth, uint8_t stencil, uint32_t numRects, void* pRects);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_ClearRenderTargetView
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_ClearRenderTargetView
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearRenderTargetView(void* i, uintptr_t pRenderTargetView, void* colorRGBA, uint32_t numRects, void* pRects);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_Close
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_Close
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Close(void* i);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_CopyTextureRegion
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_CopyTextureRegion
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_CopyTextureRegion(void* i, void* pDst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, void* pSrc, void* pSrcBox);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_DrawIndexedInstanced
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_DrawIndexedInstanced
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_DrawIndexedInstanced(void* i, uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_IASetIndexBuffer
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_IASetIndexBuffer
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetIndexBuffer(void* i, void* pView);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_IASetPrimitiveTopology
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_IASetPrimitiveTopology
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetPrimitiveTopology(void* i, int32_t primitiveTopology);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_IASetVertexBuffers
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_IASetVertexBuffers
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetVertexBuffers(void* i, uint32_t startSlot, uint32_t numViews, void* pViews);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_OMSetRenderTargets
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_OMSetRenderTargets
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetRenderTargets(void* i, uint32_t numRenderTargetDescriptors, void* pRenderTargetDescriptors, int rtsSingleHandleToDescriptorRange, void* pDepthStencilDescriptor);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_OMSetStencilRef
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_OMSetStencilRef
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetStencilRef(void* i, uint32_t stencilRef);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_Release
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_Release
|
||||
// uint32_t Ebitengine_ID3D12GraphicsCommandList_Release(void* i);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_Reset
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_Reset
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Reset(void* i, void* pAllocator, void* pInitialState);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_ResourceBarrier
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_ResourceBarrier
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ResourceBarrier(void* i, uint32_t numBarriers, void* pBarriers);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_RSSetViewports
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_RSSetViewports
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetViewports(void* i, uint32_t numViewports, void* pViewports);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_RSSetScissorRects
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_RSSetScissorRects
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetScissorRects(void* i, uint32_t numRects, void* pRects);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_SetDescriptorHeaps
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_SetDescriptorHeaps
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetDescriptorHeaps(void* i, uint32_t numDescriptorHeaps, void* ppDescriptorHeaps);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(void* i, uint32_t rootParameterIndex, uint64_t baseDescriptorPtr);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_SetGraphicsRootSignature
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_SetGraphicsRootSignature
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootSignature(void* i, void* pRootSignature);
|
||||
//
|
||||
// #cgo noescape ID3D12GraphicsCommandList_SetPipelineState
|
||||
// #cgo nocallback ID3D12GraphicsCommandList_SetPipelineState
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetPipelineState(void* i, void* pPipelineState);
|
||||
import "C"
|
||||
|
||||
@@ -111,6 +249,44 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func _D3D12_RESOURCE_STATE_PRESENT() _D3D12_RESOURCE_STATES {
|
||||
// This value depends on the environment.
|
||||
return _D3D12_RESOURCE_STATES(C.Ebitengine_D3D12_RESOURCE_STATE_PRESENT())
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_ExecuteCommandLists(i *_ID3D12CommandQueue, ppCommandLists []*_ID3D12GraphicsCommandList) {
|
||||
var ppCommandListsPtr **_ID3D12GraphicsCommandList
|
||||
if len(ppCommandLists) > 0 {
|
||||
ppCommandListsPtr = &ppCommandLists[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12CommandQueue_ExecuteCommandLists(unsafe.Pointer(i), C.uint32_t(len(ppCommandLists)), unsafe.Pointer(ppCommandListsPtr))
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_PresentX(i *_ID3D12CommandQueue, planeCount uint32, pPlaneParameters *_D3D12XBOX_PRESENT_PLANE_PARAMETERS, pPresentParameters *_D3D12XBOX_PRESENT_PARAMETERS) uintptr {
|
||||
r := C.Ebitengine_ID3D12CommandQueue_PresentX(unsafe.Pointer(i), C.uint32_t(planeCount), unsafe.Pointer(pPlaneParameters), unsafe.Pointer(pPresentParameters))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_Release(i *_ID3D12CommandQueue) uint32 {
|
||||
r := C.Ebitengine_ID3D12CommandQueue_Release(unsafe.Pointer(i))
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_ResumeX(i *_ID3D12CommandQueue) uintptr {
|
||||
r := C.Ebitengine_ID3D12CommandQueue_ResumeX(unsafe.Pointer(i))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_Signal(i *_ID3D12CommandQueue, pFence *_ID3D12Fence, value uint64) uintptr {
|
||||
r := C.Ebitengine_ID3D12CommandQueue_Signal(unsafe.Pointer(i), unsafe.Pointer(pFence), C.uint64_t(value))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_SuspendX(i *_ID3D12CommandQueue, flags uint32) uintptr {
|
||||
r := C.Ebitengine_ID3D12CommandQueue_SuspendX(unsafe.Pointer(i), C.uint32_t(flags))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ClearDepthStencilView(i *_ID3D12GraphicsCommandList, depthStencilView _D3D12_CPU_DESCRIPTOR_HANDLE, clearFlags _D3D12_CLEAR_FLAGS, depth float32, stencil uint8, rects []_D3D12_RECT) {
|
||||
var pRects *_D3D12_RECT
|
||||
if len(rects) > 0 {
|
||||
|
||||
Generated
Vendored
+28
@@ -20,6 +20,34 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func _D3D12_RESOURCE_STATE_PRESENT() _D3D12_RESOURCE_STATES {
|
||||
return 0
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_ExecuteCommandLists(i *_ID3D12CommandQueue, ppCommandLists []*_ID3D12GraphicsCommandList) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_PresentX(i *_ID3D12CommandQueue, planeCount uint32, pPlaneParameters *_D3D12XBOX_PRESENT_PLANE_PARAMETERS, pPresentParameters *_D3D12XBOX_PRESENT_PARAMETERS) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_Release(i *_ID3D12CommandQueue) uint32 {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_ResumeX(i *_ID3D12CommandQueue) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_Signal(i *_ID3D12CommandQueue, pFence *_ID3D12Fence, value uint64) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12CommandQueue_SuspendX(i *_ID3D12CommandQueue, flags uint32) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ClearDepthStencilView(i *_ID3D12GraphicsCommandList, depthStencilView _D3D12_CPU_DESCRIPTOR_HANDLE, clearFlags _D3D12_CLEAR_FLAGS, depth float32, stencil uint8, rects []_D3D12_RECT) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
Generated
Vendored
+25
-24
@@ -343,7 +343,6 @@ const (
|
||||
_D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT _D3D12_RESOURCE_STATES = 0x200
|
||||
_D3D12_RESOURCE_STATE_COPY_DEST _D3D12_RESOURCE_STATES = 0x400
|
||||
_D3D12_RESOURCE_STATE_COPY_SOURCE _D3D12_RESOURCE_STATES = 0x800
|
||||
_D3D12_RESOURCE_STATE_PRESENT _D3D12_RESOURCE_STATES = 0
|
||||
)
|
||||
|
||||
func _D3D12_RESOURCE_STATE_GENERIC_READ() _D3D12_RESOURCE_STATES {
|
||||
@@ -1066,33 +1065,24 @@ type _ID3D12CommandQueue_Vtbl struct {
|
||||
Wait uintptr
|
||||
GetTimestampFrequency uintptr
|
||||
GetClockCalibration uintptr
|
||||
GetDesc uintptr // Is this another function for Xbox?
|
||||
|
||||
// These members are for Xbox.
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
SuspendX uintptr
|
||||
ResumeX uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr // Is this GetDesc for Xbox?
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
PresentX uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
GetDesc uintptr
|
||||
}
|
||||
|
||||
func (i *_ID3D12CommandQueue) ExecuteCommandLists(ppCommandLists []*_ID3D12GraphicsCommandList) {
|
||||
_, _, _ = syscall.Syscall(i.vtbl.ExecuteCommandLists, 3, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(len(ppCommandLists)), uintptr(unsafe.Pointer(&ppCommandLists[0])))
|
||||
if microsoftgdk.IsXbox() {
|
||||
_ID3D12CommandQueue_ExecuteCommandLists(i, ppCommandLists)
|
||||
} else {
|
||||
_, _, _ = syscall.Syscall(i.vtbl.ExecuteCommandLists, 3, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(len(ppCommandLists)), uintptr(unsafe.Pointer(&ppCommandLists[0])))
|
||||
}
|
||||
runtime.KeepAlive(ppCommandLists)
|
||||
}
|
||||
|
||||
func (i *_ID3D12CommandQueue) PresentX(planeCount uint32, pPlaneParameters *_D3D12XBOX_PRESENT_PLANE_PARAMETERS, pPresentParameters *_D3D12XBOX_PRESENT_PARAMETERS) error {
|
||||
r, _, _ := syscall.Syscall6(i.vtbl.PresentX, 4, uintptr(unsafe.Pointer(i)), uintptr(planeCount), uintptr(unsafe.Pointer(pPlaneParameters)), uintptr(unsafe.Pointer(pPresentParameters)), 0, 0)
|
||||
if !microsoftgdk.IsXbox() {
|
||||
panic("directx: ID3D12CommandQueue::PresentX is only available on Xbox")
|
||||
}
|
||||
r := _ID3D12CommandQueue_PresentX(i, planeCount, pPlaneParameters, pPresentParameters)
|
||||
runtime.KeepAlive(pPlaneParameters)
|
||||
runtime.KeepAlive(pPresentParameters)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
@@ -1102,12 +1092,18 @@ func (i *_ID3D12CommandQueue) PresentX(planeCount uint32, pPlaneParameters *_D3D
|
||||
}
|
||||
|
||||
func (i *_ID3D12CommandQueue) Release() uint32 {
|
||||
if microsoftgdk.IsXbox() {
|
||||
return _ID3D12CommandQueue_Release(i)
|
||||
}
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *_ID3D12CommandQueue) ResumeX() error {
|
||||
if r, _, _ := syscall.Syscall(i.vtbl.ResumeX, 1, uintptr(unsafe.Pointer(i)), 0, 0); uint32(r) != uint32(windows.S_OK) {
|
||||
if !microsoftgdk.IsXbox() {
|
||||
panic("directx: ID3D12CommandQueue::ResumeX is only available on Xbox")
|
||||
}
|
||||
if r := _ID3D12CommandQueue_ResumeX(i); uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: ID3D12CommandQueue::ResumeX failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
@@ -1115,7 +1111,9 @@ func (i *_ID3D12CommandQueue) ResumeX() error {
|
||||
|
||||
func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
||||
var r uintptr
|
||||
if is64bit {
|
||||
if microsoftgdk.IsXbox() {
|
||||
r = _ID3D12CommandQueue_Signal(i, signal, value)
|
||||
} else if is64bit {
|
||||
r, _, _ = syscall.Syscall(i.vtbl.Signal, 3, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(signal)), uintptr(value))
|
||||
} else {
|
||||
@@ -1130,7 +1128,10 @@ func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
||||
}
|
||||
|
||||
func (i *_ID3D12CommandQueue) SuspendX(flags uint32) error {
|
||||
if r, _, _ := syscall.Syscall(i.vtbl.SuspendX, 2, uintptr(unsafe.Pointer(i)), uintptr(flags), 0); uint32(r) != uint32(windows.S_OK) {
|
||||
if !microsoftgdk.IsXbox() {
|
||||
panic("directx: ID3D12CommandQueue::SuspendX is only available on Xbox")
|
||||
}
|
||||
if r := _ID3D12CommandQueue_SuspendX(i, flags); uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: ID3D12CommandQueue::SuspendX failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
|
||||
Generated
Vendored
+16
-1
@@ -71,7 +71,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
procD3DCompile *windows.LazyProc
|
||||
procD3DCompile *windows.LazyProc
|
||||
procD3DCreateBlob *windows.LazyProc
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -93,6 +94,7 @@ func init() {
|
||||
}
|
||||
|
||||
procD3DCompile = d3dcompiler.NewProc("D3DCompile")
|
||||
procD3DCreateBlob = d3dcompiler.NewProc("D3DCreateBlob")
|
||||
}
|
||||
|
||||
func isD3DCompilerDLLAvailable() bool {
|
||||
@@ -135,6 +137,19 @@ func _D3DCompile(srcData []byte, sourceName string, pDefines []_D3D_SHADER_MACRO
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func _D3DCreateBlob(size uint) (*_ID3DBlob, error) {
|
||||
if !isD3DCompilerDLLAvailable() {
|
||||
return nil, fmt.Errorf("directx: d3dcompiler_*.dll is missing in this environment")
|
||||
}
|
||||
|
||||
var blob *_ID3DBlob
|
||||
r, _, _ := procD3DCreateBlob.Call(uintptr(size), uintptr(unsafe.Pointer(&blob)))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: D3DCreateBlob failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return blob, nil
|
||||
}
|
||||
|
||||
type _D3D_SHADER_MACRO struct {
|
||||
Name *byte
|
||||
Definition *byte
|
||||
|
||||
Generated
Vendored
+61
-40
@@ -27,34 +27,56 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
|
||||
)
|
||||
|
||||
var inputElementDescsForDX11 = []_D3D11_INPUT_ELEMENT_DESC{
|
||||
{
|
||||
SemanticName: &([]byte("POSITION\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("TEXCOORD\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
var inputElementDescsForDX11 []_D3D11_INPUT_ELEMENT_DESC
|
||||
|
||||
func init() {
|
||||
inputElementDescsForDX11 = []_D3D11_INPUT_ELEMENT_DESC{
|
||||
{
|
||||
SemanticName: &([]byte("POSITION\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("TEXCOORD\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
}
|
||||
diff := graphics.VertexFloatCount - 8
|
||||
if diff == 0 {
|
||||
return
|
||||
}
|
||||
if diff%4 != 0 {
|
||||
panic("directx: unexpected attribute layout")
|
||||
}
|
||||
for i := 0; i < diff/4; i++ {
|
||||
inputElementDescsForDX11 = append(inputElementDescsForDX11, _D3D11_INPUT_ELEMENT_DESC{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: uint32(i) + 1,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func blendFactorToBlend11(f graphicsdriver.BlendFactor, alpha bool) _D3D11_BLEND {
|
||||
@@ -482,8 +504,7 @@ func (g *graphics11) MaxImageSize() int {
|
||||
}
|
||||
|
||||
func (g *graphics11) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
vs, ps, offsets := hlsl.Compile(program)
|
||||
vsh, psh, err := compileShader(vs, ps)
|
||||
vsh, psh, err := compileShader(program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -492,7 +513,7 @@ func (g *graphics11) NewShader(program *shaderir.Program) (graphicsdriver.Shader
|
||||
graphics: g,
|
||||
id: g.genNextShaderID(),
|
||||
uniformTypes: program.Uniforms,
|
||||
uniformOffsets: offsets,
|
||||
uniformOffsets: hlsl.UniformVariableOffsetsInDwords(program),
|
||||
vertexShaderBlob: vsh,
|
||||
pixelShaderBlob: psh,
|
||||
}
|
||||
@@ -515,14 +536,14 @@ func (g *graphics11) removeShader(s *shader11) {
|
||||
delete(g.shaders, s.id)
|
||||
}
|
||||
|
||||
func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
// Remove bound textures first. This is needed to avoid warnings on the debugger.
|
||||
g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil)
|
||||
srvs := [graphics.ShaderImageCount]*_ID3D11ShaderResourceView{}
|
||||
srvs := [graphics.ShaderSrcImageCount]*_ID3D11ShaderResourceView{}
|
||||
g.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||
|
||||
dst := g.images[dstID]
|
||||
var srcs [graphics.ShaderImageCount]*image11
|
||||
var srcs [graphics.ShaderSrcImageCount]*image11
|
||||
for i, id := range srcIDs {
|
||||
img := g.images[id]
|
||||
if img == nil {
|
||||
@@ -543,7 +564,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
||||
},
|
||||
})
|
||||
|
||||
if err := dst.setAsRenderTarget(fillRule != graphicsdriver.FillAll); err != nil {
|
||||
if err := dst.setAsRenderTarget(fillRule != graphicsdriver.FillRuleFillAll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -553,7 +574,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
||||
return err
|
||||
}
|
||||
|
||||
if fillRule == graphicsdriver.FillAll {
|
||||
if fillRule == graphicsdriver.FillRuleFillAll {
|
||||
bs, err := g.blendState(blend, noStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -578,9 +599,9 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
||||
})
|
||||
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
case graphicsdriver.FillRuleFillAll:
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
case graphicsdriver.NonZero:
|
||||
case graphicsdriver.FillRuleNonZero:
|
||||
bs, err := g.blendState(blend, incrementStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -592,7 +613,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
case graphicsdriver.EvenOdd:
|
||||
case graphicsdriver.FillRuleEvenOdd:
|
||||
bs, err := g.blendState(blend, invertStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -606,7 +627,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
bs, err := g.blendState(blend, drawWithStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Generated
Vendored
+38
-39
@@ -17,6 +17,7 @@ package directx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -48,7 +49,7 @@ type graphics12 struct {
|
||||
renderTargets [frameCount]*_ID3D12Resource
|
||||
framePipelineToken _D3D12XBOX_FRAME_PIPELINE_TOKEN
|
||||
|
||||
fence *_ID3D12Fence
|
||||
fences [frameCount]*_ID3D12Fence
|
||||
fenceValues [frameCount]uint64
|
||||
fenceWaitEvent windows.Handle
|
||||
|
||||
@@ -93,6 +94,7 @@ type graphics12 struct {
|
||||
shaders map[graphicsdriver.ShaderID]*shader12
|
||||
nextShaderID graphicsdriver.ShaderID
|
||||
disposedShaders [frameCount][]*shader12
|
||||
tmpUniforms []uint32
|
||||
|
||||
vsyncEnabled bool
|
||||
|
||||
@@ -208,7 +210,7 @@ func (g *graphics12) initializeDesktop(useWARP bool, useDebugLayer bool, feature
|
||||
}
|
||||
g.device = (*_ID3D12Device)(d)
|
||||
|
||||
if err := g.initializeMembers(g.frameIndex); err != nil {
|
||||
if err := g.initializeMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -224,8 +226,6 @@ func (g *graphics12) initializeDesktop(useWARP bool, useDebugLayer bool, feature
|
||||
}
|
||||
|
||||
func (g *graphics12) initializeXbox(useWARP bool, useDebugLayer bool) (ferr error) {
|
||||
g = &graphics12{}
|
||||
|
||||
if err := d3d12x.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -245,7 +245,7 @@ func (g *graphics12) initializeXbox(useWARP bool, useDebugLayer bool) (ferr erro
|
||||
}
|
||||
g.device = (*_ID3D12Device)(d)
|
||||
|
||||
if err := g.initializeMembers(g.frameIndex); err != nil {
|
||||
if err := g.initializeMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (g *graphics12) registerFrameEventForXbox() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics12) initializeMembers(frameIndex int) (ferr error) {
|
||||
func (g *graphics12) initializeMembers() (ferr error) {
|
||||
// Create an event for a fence.
|
||||
e, err := windows.CreateEventEx(nil, nil, 0, windows.EVENT_MODIFY_STATE|windows.SYNCHRONIZE)
|
||||
if err != nil {
|
||||
@@ -355,18 +355,19 @@ func (g *graphics12) initializeMembers(frameIndex int) (ferr error) {
|
||||
}
|
||||
|
||||
// Create a frame fence.
|
||||
f, err := g.device.CreateFence(0, _D3D12_FENCE_FLAG_NONE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.fence = f
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
g.fence.Release()
|
||||
g.fence = nil
|
||||
for i := range frameCount {
|
||||
f, err := g.device.CreateFence(0, _D3D12_FENCE_FLAG_NONE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}()
|
||||
g.fenceValues[frameIndex]++
|
||||
g.fences[i] = f
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
g.fences[i].Release()
|
||||
g.fences[i] = nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Create command lists.
|
||||
dcl, err := g.device.CreateCommandList(0, _D3D12_COMMAND_LIST_TYPE_DIRECT, g.drawCommandAllocators[0], nil)
|
||||
@@ -537,7 +538,7 @@ func (g *graphics12) initSwapChainXbox(width, height int) (ferr error) {
|
||||
},
|
||||
Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
||||
Flags: _D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
||||
}, _D3D12_RESOURCE_STATE_PRESENT, &_D3D12_CLEAR_VALUE{
|
||||
}, _D3D12_RESOURCE_STATE_PRESENT(), &_D3D12_CLEAR_VALUE{
|
||||
Format: _DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -569,10 +570,6 @@ func (g *graphics12) resizeSwapChainDesktop(width, height int) error {
|
||||
}
|
||||
g.releaseResources(g.frameIndex)
|
||||
|
||||
for i := 0; i < frameCount; i++ {
|
||||
g.fenceValues[i] = g.fenceValues[g.frameIndex]
|
||||
}
|
||||
|
||||
for _, r := range g.renderTargets {
|
||||
r.Release()
|
||||
}
|
||||
@@ -676,7 +673,7 @@ func (g *graphics12) End(present bool) error {
|
||||
|
||||
// screenImage can be nil in tests.
|
||||
if present && g.screenImage != nil {
|
||||
if rb, ok := g.screenImage.transiteState(_D3D12_RESOURCE_STATE_PRESENT); ok {
|
||||
if rb, ok := g.screenImage.transiteState(_D3D12_RESOURCE_STATE_PRESENT()); ok {
|
||||
g.drawCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb})
|
||||
}
|
||||
}
|
||||
@@ -738,6 +735,9 @@ func (g *graphics12) presentDesktop() error {
|
||||
}
|
||||
|
||||
func (g *graphics12) presentXbox() error {
|
||||
var pinner runtime.Pinner
|
||||
pinner.Pin(&g.renderTargets[g.frameIndex])
|
||||
defer pinner.Unpin()
|
||||
return g.commandQueue.PresentX(1, &_D3D12XBOX_PRESENT_PLANE_PARAMETERS{
|
||||
Token: g.framePipelineToken,
|
||||
ResourceCount: 1,
|
||||
@@ -746,8 +746,9 @@ func (g *graphics12) presentXbox() error {
|
||||
}
|
||||
|
||||
func (g *graphics12) moveToNextFrame() error {
|
||||
g.fenceValues[g.frameIndex]++
|
||||
fv := g.fenceValues[g.frameIndex]
|
||||
if err := g.commandQueue.Signal(g.fence, fv); err != nil {
|
||||
if err := g.commandQueue.Signal(g.fences[g.frameIndex], fv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -762,15 +763,14 @@ func (g *graphics12) moveToNextFrame() error {
|
||||
g.frameIndex = idx
|
||||
}
|
||||
|
||||
if g.fence.GetCompletedValue() < g.fenceValues[g.frameIndex] {
|
||||
if err := g.fence.SetEventOnCompletion(g.fenceValues[g.frameIndex], g.fenceWaitEvent); err != nil {
|
||||
if g.fences[g.frameIndex].GetCompletedValue() < g.fenceValues[g.frameIndex] {
|
||||
if err := g.fences[g.frameIndex].SetEventOnCompletion(g.fenceValues[g.frameIndex], g.fenceWaitEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
g.fenceValues[g.frameIndex] = fv + 1
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -858,17 +858,17 @@ func (g *graphics12) flushCommandList(commandList *_ID3D12GraphicsCommandList) e
|
||||
}
|
||||
|
||||
func (g *graphics12) waitForCommandQueue() error {
|
||||
g.fenceValues[g.frameIndex]++
|
||||
fv := g.fenceValues[g.frameIndex]
|
||||
if err := g.commandQueue.Signal(g.fence, fv); err != nil {
|
||||
if err := g.commandQueue.Signal(g.fences[g.frameIndex], fv); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.fence.SetEventOnCompletion(fv, g.fenceWaitEvent); err != nil {
|
||||
if err := g.fences[g.frameIndex].SetEventOnCompletion(fv, g.fenceWaitEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
||||
return err
|
||||
}
|
||||
g.fenceValues[g.frameIndex]++
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1064,8 +1064,7 @@ func (g *graphics12) MaxImageSize() int {
|
||||
}
|
||||
|
||||
func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
vs, ps, offsets := hlsl.Compile(program)
|
||||
vsh, psh, err := compileShader(vs, ps)
|
||||
vsh, psh, err := compileShader(program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1074,7 +1073,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader
|
||||
graphics: g,
|
||||
id: g.genNextShaderID(),
|
||||
uniformTypes: program.Uniforms,
|
||||
uniformOffsets: offsets,
|
||||
uniformOffsets: hlsl.UniformVariableOffsetsInDwords(program),
|
||||
vertexShader: vsh,
|
||||
pixelShader: psh,
|
||||
}
|
||||
@@ -1082,7 +1081,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("directx: shader ID is invalid")
|
||||
}
|
||||
@@ -1093,7 +1092,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
||||
|
||||
// Release constant buffers when too many ones will be created.
|
||||
numPipelines := 1
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
numPipelines = 2
|
||||
}
|
||||
if len(g.pipelineStates.constantBuffers[g.frameIndex])+numPipelines > numDescriptorsPerFrame {
|
||||
@@ -1109,7 +1108,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
||||
resourceBarriers = append(resourceBarriers, rb)
|
||||
}
|
||||
|
||||
var srcImages [graphics.ShaderImageCount]*image12
|
||||
var srcImages [graphics.ShaderSrcImageCount]*image12
|
||||
for i, srcID := range srcs {
|
||||
src := g.images[srcID]
|
||||
if src == nil {
|
||||
@@ -1125,12 +1124,12 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
||||
g.drawCommandList.ResourceBarrier(resourceBarriers)
|
||||
}
|
||||
|
||||
if err := dst.setAsRenderTarget(g.drawCommandList, g.device, fillRule != graphicsdriver.FillAll); err != nil {
|
||||
if err := dst.setAsRenderTarget(g.drawCommandList, g.device, fillRule != graphicsdriver.FillRuleFillAll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shader := g.shaders[shaderID]
|
||||
adjustedUniforms := adjustUniforms(shader.uniformTypes, shader.uniformOffsets, uniforms)
|
||||
g.tmpUniforms = appendAdjustedUniforms(g.tmpUniforms[:0], shader.uniformTypes, shader.uniformOffsets, uniforms)
|
||||
|
||||
w, h := dst.internalSize()
|
||||
g.needFlushDrawCommandList = true
|
||||
@@ -1158,7 +1157,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
||||
Format: _DXGI_FORMAT_R32_UINT,
|
||||
})
|
||||
|
||||
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, dst.screen, srcImages, shader, dstRegions, adjustedUniforms, blend, indexOffset, fillRule); err != nil {
|
||||
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, dst.screen, srcImages, shader, dstRegions, g.tmpUniforms, blend, indexOffset, fillRule); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+18
-5
@@ -147,9 +147,7 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
}
|
||||
|
||||
type graphicsInfra struct {
|
||||
factory *_IDXGIFactory
|
||||
swapChain *_IDXGISwapChain
|
||||
swapChain4 *_IDXGISwapChain4
|
||||
*graphicsInfraResources
|
||||
|
||||
allowTearing bool
|
||||
|
||||
@@ -160,14 +158,24 @@ type graphicsInfra struct {
|
||||
lastTime time.Time
|
||||
|
||||
bufferCount int
|
||||
|
||||
cleanup runtime.Cleanup
|
||||
}
|
||||
|
||||
type graphicsInfraResources struct {
|
||||
factory *_IDXGIFactory
|
||||
swapChain *_IDXGISwapChain
|
||||
swapChain4 *_IDXGISwapChain4
|
||||
}
|
||||
|
||||
// newGraphicsInfra takes the ownership of the given factory.
|
||||
func newGraphicsInfra(factory *_IDXGIFactory) (*graphicsInfra, error) {
|
||||
g := &graphicsInfra{
|
||||
factory: factory,
|
||||
graphicsInfraResources: &graphicsInfraResources{
|
||||
factory: factory,
|
||||
},
|
||||
}
|
||||
runtime.SetFinalizer(g, (*graphicsInfra).release)
|
||||
g.cleanup = runtime.AddCleanup(g, (*graphicsInfraResources).releaseResources, g.graphicsInfraResources)
|
||||
|
||||
if f, err := g.factory.QueryInterface(&_IID_IDXGIFactory5); err == nil && f != nil {
|
||||
factory := (*_IDXGIFactory5)(f)
|
||||
@@ -183,6 +191,11 @@ func newGraphicsInfra(factory *_IDXGIFactory) (*graphicsInfra, error) {
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) release() {
|
||||
g.releaseResources()
|
||||
g.cleanup.Stop()
|
||||
}
|
||||
|
||||
func (g *graphicsInfraResources) releaseResources() {
|
||||
if g.factory != nil {
|
||||
g.factory.Release()
|
||||
g.factory = nil
|
||||
|
||||
Generated
Vendored
+58
-36
@@ -23,34 +23,56 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
)
|
||||
|
||||
var inputElementDescsForDX12 = []_D3D12_INPUT_ELEMENT_DESC{
|
||||
{
|
||||
SemanticName: &([]byte("POSITION\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("TEXCOORD\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
var inputElementDescsForDX12 []_D3D12_INPUT_ELEMENT_DESC
|
||||
|
||||
func init() {
|
||||
inputElementDescsForDX12 = []_D3D12_INPUT_ELEMENT_DESC{
|
||||
{
|
||||
SemanticName: &([]byte("POSITION\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("TEXCOORD\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
}
|
||||
diff := graphics.VertexFloatCount - 8
|
||||
if diff == 0 {
|
||||
return
|
||||
}
|
||||
if diff%4 != 0 {
|
||||
panic("directx: unexpected attribute layout")
|
||||
}
|
||||
for i := 0; i < diff/4; i++ {
|
||||
inputElementDescsForDX12 = append(inputElementDescsForDX12, _D3D12_INPUT_ELEMENT_DESC{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: uint32(i) + 1,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D12_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const numDescriptorsPerFrame = 32
|
||||
@@ -128,7 +150,7 @@ type pipelineStates struct {
|
||||
constantBufferMaps [frameCount][]uintptr
|
||||
}
|
||||
|
||||
const numConstantBufferAndSourceTextures = 1 + graphics.ShaderImageCount
|
||||
const numConstantBufferAndSourceTextures = 1 + graphics.ShaderSrcImageCount
|
||||
|
||||
func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
||||
// Create a CBV/SRV/UAV descriptor heap.
|
||||
@@ -180,7 +202,7 @@ func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*image12, shader *shader12, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, fillRule graphicsdriver.FillRule) error {
|
||||
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderSrcImageCount]*image12, shader *shader12, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, fillRule graphicsdriver.FillRule) error {
|
||||
idx := len(p.constantBuffers[frameIndex])
|
||||
if idx >= numDescriptorsPerFrame {
|
||||
return fmt.Errorf("directx: too many constant buffers")
|
||||
@@ -289,7 +311,7 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D
|
||||
}
|
||||
commandList.SetGraphicsRootDescriptorTable(2, sh)
|
||||
|
||||
if fillRule == graphicsdriver.FillAll {
|
||||
if fillRule == graphicsdriver.FillRuleFillAll {
|
||||
s, err := shader.pipelineState(blend, noStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -307,16 +329,16 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D
|
||||
},
|
||||
})
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
case graphicsdriver.FillRuleFillAll:
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
case graphicsdriver.NonZero:
|
||||
case graphicsdriver.FillRuleNonZero:
|
||||
s, err := shader.pipelineState(blend, incrementStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
case graphicsdriver.EvenOdd:
|
||||
case graphicsdriver.FillRuleEvenOdd:
|
||||
s, err := shader.pipelineState(blend, invertStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -325,7 +347,7 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
s, err := shader.pipelineState(blend, drawWithStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -354,7 +376,7 @@ func (p *pipelineStates) ensureRootSignature(device *_ID3D12Device) (rootSignatu
|
||||
}
|
||||
srv := _D3D12_DESCRIPTOR_RANGE{
|
||||
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // t0
|
||||
NumDescriptors: graphics.ShaderImageCount,
|
||||
NumDescriptors: graphics.ShaderSrcImageCount,
|
||||
BaseShaderRegister: 0,
|
||||
RegisterSpace: 0,
|
||||
OffsetInDescriptorsFromTableStart: 1,
|
||||
|
||||
Generated
Vendored
+5
-4
@@ -29,6 +29,7 @@ type shader11 struct {
|
||||
uniformOffsets []int
|
||||
vertexShaderBlob *_ID3DBlob
|
||||
pixelShaderBlob *_ID3DBlob
|
||||
tmpUniforms []uint32
|
||||
|
||||
inputLayout *_ID3D11InputLayout
|
||||
vertexShader *_ID3D11VertexShader
|
||||
@@ -78,7 +79,7 @@ func (s *shader11) disposeImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image11) error {
|
||||
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderSrcImageCount]*image11) error {
|
||||
vs, err := s.ensureVertexShader()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -105,16 +106,16 @@ func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image
|
||||
s.graphics.deviceContext.PSSetConstantBuffers(0, []*_ID3D11Buffer{cb})
|
||||
|
||||
// Send the constant buffer data.
|
||||
uniforms = adjustUniforms(s.uniformTypes, s.uniformOffsets, uniforms)
|
||||
s.tmpUniforms = appendAdjustedUniforms(s.tmpUniforms[:0], s.uniformTypes, s.uniformOffsets, uniforms)
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := s.graphics.deviceContext.Map(unsafe.Pointer(cb), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*uint32)(mapped.pData), len(uniforms)), uniforms)
|
||||
copy(unsafe.Slice((*uint32)(mapped.pData), len(s.tmpUniforms)), s.tmpUniforms)
|
||||
s.graphics.deviceContext.Unmap(unsafe.Pointer(cb), 0)
|
||||
|
||||
// Set the render sources.
|
||||
var srvs [graphics.ShaderImageCount]*_ID3D11ShaderResourceView
|
||||
var srvs [graphics.ShaderSrcImageCount]*_ID3D11ShaderResourceView
|
||||
for i, src := range srcs {
|
||||
if src == nil {
|
||||
continue
|
||||
|
||||
Generated
Vendored
+126
-43
@@ -16,18 +16,67 @@ package directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
|
||||
)
|
||||
|
||||
const (
|
||||
VertexShaderProfile = "vs_4_0"
|
||||
PixelShaderProfile = "ps_4_0"
|
||||
|
||||
VertexShaderEntryPoint = "VSMain"
|
||||
PixelShaderEntryPoint = "PSMain"
|
||||
)
|
||||
|
||||
type fxcPair struct {
|
||||
vertex []byte
|
||||
pixel []byte
|
||||
}
|
||||
|
||||
type precompiledFXCs struct {
|
||||
binaries map[shaderir.SourceHash]fxcPair
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (c *precompiledFXCs) put(hash shaderir.SourceHash, vertex, pixel []byte) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if c.binaries == nil {
|
||||
c.binaries = map[shaderir.SourceHash]fxcPair{}
|
||||
}
|
||||
if _, ok := c.binaries[hash]; ok {
|
||||
panic(fmt.Sprintf("directx: the precompiled library for the hash %s is already registered", hash.String()))
|
||||
}
|
||||
c.binaries[hash] = fxcPair{
|
||||
vertex: vertex,
|
||||
pixel: pixel,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *precompiledFXCs) get(hash shaderir.SourceHash) ([]byte, []byte) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
f := c.binaries[hash]
|
||||
return f.vertex, f.pixel
|
||||
}
|
||||
|
||||
var thePrecompiledFXCs precompiledFXCs
|
||||
|
||||
func RegisterPrecompiledFXCs(source []byte, vertex, pixel []byte) {
|
||||
thePrecompiledFXCs.put(shaderir.CalcSourceHash(source), vertex, pixel)
|
||||
}
|
||||
|
||||
var vertexShaderCache = map[string]*_ID3DBlob{}
|
||||
|
||||
func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
var flag uint32 = uint32(_D3DCOMPILE_OPTIMIZATION_LEVEL3)
|
||||
|
||||
func compileShader(program *shaderir.Program) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
defer func() {
|
||||
if ferr == nil {
|
||||
return
|
||||
@@ -40,6 +89,22 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
}
|
||||
}()
|
||||
|
||||
if vshBin, pshBin := thePrecompiledFXCs.get(program.SourceHash); vshBin != nil && pshBin != nil {
|
||||
var err error
|
||||
if vsh, err = _D3DCreateBlob(uint(len(vshBin))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if psh, err = _D3DCreateBlob(uint(len(pshBin))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
copy(unsafe.Slice((*byte)(vsh.GetBufferPointer()), vsh.GetBufferSize()), vshBin)
|
||||
copy(unsafe.Slice((*byte)(psh.GetBufferPointer()), psh.GetBufferSize()), pshBin)
|
||||
return vsh, psh, nil
|
||||
}
|
||||
|
||||
vs, ps, _, _ := hlsl.Compile(program)
|
||||
var flag uint32 = uint32(_D3DCOMPILE_OPTIMIZATION_LEVEL3)
|
||||
|
||||
var wg errgroup.Group
|
||||
|
||||
// Vertex shaders are likely the same. If so, reuse the same _ID3DBlob.
|
||||
@@ -56,7 +121,7 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
}
|
||||
}()
|
||||
wg.Go(func() error {
|
||||
v, err := _D3DCompile([]byte(vs), "shader", nil, nil, "VSMain", "vs_4_0", flag, 0)
|
||||
v, err := _D3DCompile([]byte(vs), "shader", nil, nil, VertexShaderEntryPoint, VertexShaderProfile, flag, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("directx: D3DCompile for VSMain failed, original source: %s, %w", vs, err)
|
||||
}
|
||||
@@ -65,7 +130,7 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
})
|
||||
}
|
||||
wg.Go(func() error {
|
||||
p, err := _D3DCompile([]byte(ps), "shader", nil, nil, "PSMain", "ps_4_0", flag, 0)
|
||||
p, err := _D3DCompile([]byte(ps), "shader", nil, nil, PixelShaderEntryPoint, PixelShaderProfile, flag, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("directx: D3DCompile for PSMain failed, original source: %s, %w", ps, err)
|
||||
}
|
||||
@@ -77,17 +142,20 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return
|
||||
return vsh, psh, nil
|
||||
}
|
||||
|
||||
func constantBufferSize(uniformTypes []shaderir.Type, uniformOffsets []int) int {
|
||||
var size int
|
||||
for i, typ := range uniformTypes {
|
||||
if size < uniformOffsets[i]/4 {
|
||||
size = uniformOffsets[i] / 4
|
||||
if size < uniformOffsets[i] {
|
||||
size = uniformOffsets[i]
|
||||
}
|
||||
|
||||
switch typ.Main {
|
||||
case shaderir.Bool:
|
||||
// Bool is 4 bytes in HLSL.
|
||||
size += 1
|
||||
case shaderir.Float:
|
||||
size += 1
|
||||
case shaderir.Int:
|
||||
@@ -107,6 +175,8 @@ func constantBufferSize(uniformTypes []shaderir.Type, uniformOffsets []int) int
|
||||
case shaderir.Array:
|
||||
// Each element is aligned to the boundary.
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Bool:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Float:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Int:
|
||||
@@ -133,33 +203,39 @@ func constantBufferSize(uniformTypes []shaderir.Type, uniformOffsets []int) int
|
||||
return size
|
||||
}
|
||||
|
||||
func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms []uint32) []uint32 {
|
||||
var fs []uint32
|
||||
func appendAdjustedUniforms(dst []uint32, uniformTypes []shaderir.Type, uniformOffsets []int, uniforms []uint32) []uint32 {
|
||||
// Note that HLSL's matrices are row-major, while GLSL and MSL are column-major.
|
||||
// Transpose matrices so that users can access matrix indices in the same way as GLSL and MSL.
|
||||
// For packing rule, see https://github.com/microsoft/DirectXShaderCompiler/wiki/Buffer-Packing
|
||||
|
||||
var idx int
|
||||
for i, typ := range uniformTypes {
|
||||
if len(fs) < uniformOffsets[i]/4 {
|
||||
fs = append(fs, make([]uint32, uniformOffsets[i]/4-len(fs))...)
|
||||
if len(dst) < uniformOffsets[i] {
|
||||
dst = append(dst, make([]uint32, uniformOffsets[i]-len(dst))...)
|
||||
}
|
||||
|
||||
n := typ.Uint32Count()
|
||||
n := typ.DwordCount()
|
||||
switch typ.Main {
|
||||
case shaderir.Bool:
|
||||
// Bool is 4 bytes in HLSL.
|
||||
dst = append(dst, uniforms[idx:idx+1]...)
|
||||
case shaderir.Float:
|
||||
fs = append(fs, uniforms[idx:idx+1]...)
|
||||
dst = append(dst, uniforms[idx:idx+1]...)
|
||||
case shaderir.Int:
|
||||
fs = append(fs, uniforms[idx:idx+1]...)
|
||||
dst = append(dst, uniforms[idx:idx+1]...)
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
fs = append(fs, uniforms[idx:idx+2]...)
|
||||
dst = append(dst, uniforms[idx:idx+2]...)
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
fs = append(fs, uniforms[idx:idx+3]...)
|
||||
dst = append(dst, uniforms[idx:idx+3]...)
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
fs = append(fs, uniforms[idx:idx+4]...)
|
||||
dst = append(dst, uniforms[idx:idx+4]...)
|
||||
case shaderir.Mat2:
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
uniforms[idx+0], uniforms[idx+2], 0, 0,
|
||||
uniforms[idx+1], uniforms[idx+3],
|
||||
)
|
||||
case shaderir.Mat3:
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
uniforms[idx+0], uniforms[idx+3], uniforms[idx+6], 0,
|
||||
uniforms[idx+1], uniforms[idx+4], uniforms[idx+7], 0,
|
||||
uniforms[idx+2], uniforms[idx+5], uniforms[idx+8],
|
||||
@@ -169,14 +245,14 @@ func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms
|
||||
// In DirectX, the NDC's Y direction (upward) and the framebuffer's Y direction (downward) don't
|
||||
// match. Then, the Y direction must be inverted.
|
||||
// Invert the sign bits as float32 values.
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
uniforms[idx+0], uniforms[idx+4], uniforms[idx+8], uniforms[idx+12],
|
||||
uniforms[idx+1]^(1<<31), uniforms[idx+5]^(1<<31), uniforms[idx+9]^(1<<31), uniforms[idx+13]^(1<<31),
|
||||
uniforms[idx+2], uniforms[idx+6], uniforms[idx+10], uniforms[idx+14],
|
||||
uniforms[idx+3], uniforms[idx+7], uniforms[idx+11], uniforms[idx+15],
|
||||
)
|
||||
} else {
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
uniforms[idx+0], uniforms[idx+4], uniforms[idx+8], uniforms[idx+12],
|
||||
uniforms[idx+1], uniforms[idx+5], uniforms[idx+9], uniforms[idx+13],
|
||||
uniforms[idx+2], uniforms[idx+6], uniforms[idx+10], uniforms[idx+14],
|
||||
@@ -186,63 +262,70 @@ func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms
|
||||
case shaderir.Array:
|
||||
// Each element is aligned to the boundary.
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Bool:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
dst = append(dst, uniforms[idx+j])
|
||||
if j < typ.Length-1 {
|
||||
dst = append(dst, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Float:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+j])
|
||||
dst = append(dst, uniforms[idx+j])
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0, 0, 0)
|
||||
dst = append(dst, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Int:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+j])
|
||||
dst = append(dst, uniforms[idx+j])
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0, 0, 0)
|
||||
dst = append(dst, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+2*j:idx+2*(j+1)]...)
|
||||
dst = append(dst, uniforms[idx+2*j:idx+2*(j+1)]...)
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0, 0)
|
||||
dst = append(dst, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+3*j:idx+3*(j+1)]...)
|
||||
dst = append(dst, uniforms[idx+3*j:idx+3*(j+1)]...)
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0)
|
||||
dst = append(dst, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
fs = append(fs, uniforms[idx:idx+4*typ.Length]...)
|
||||
dst = append(dst, uniforms[idx:idx+4*typ.Length]...)
|
||||
case shaderir.Mat2:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
u := uniforms[idx+4*j : idx+4*(j+1)]
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
u[0], u[2], 0, 0,
|
||||
u[1], u[3], 0, 0,
|
||||
u[1], u[3],
|
||||
)
|
||||
}
|
||||
if typ.Length > 0 {
|
||||
fs = fs[:len(fs)-2]
|
||||
if j < typ.Length-1 {
|
||||
dst = append(dst, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Mat3:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
u := uniforms[idx+9*j : idx+9*(j+1)]
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
u[0], u[3], u[6], 0,
|
||||
u[1], u[4], u[7], 0,
|
||||
u[2], u[5], u[8], 0,
|
||||
u[2], u[5], u[8],
|
||||
)
|
||||
}
|
||||
if typ.Length > 0 {
|
||||
fs = fs[:len(fs)-1]
|
||||
if j < typ.Length-1 {
|
||||
dst = append(dst, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Mat4:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
u := uniforms[idx+16*j : idx+16*(j+1)]
|
||||
fs = append(fs,
|
||||
dst = append(dst,
|
||||
u[0], u[4], u[8], u[12],
|
||||
u[1], u[5], u[9], u[13],
|
||||
u[2], u[6], u[10], u[14],
|
||||
@@ -258,5 +341,5 @@ func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms
|
||||
|
||||
idx += n
|
||||
}
|
||||
return fs
|
||||
return dst
|
||||
}
|
||||
|
||||
+18
-10
@@ -30,19 +30,19 @@ type DstRegion struct {
|
||||
type FillRule int
|
||||
|
||||
const (
|
||||
FillAll FillRule = iota
|
||||
NonZero
|
||||
EvenOdd
|
||||
FillRuleFillAll FillRule = iota
|
||||
FillRuleNonZero
|
||||
FillRuleEvenOdd
|
||||
)
|
||||
|
||||
func (f FillRule) String() string {
|
||||
switch f {
|
||||
case FillAll:
|
||||
return "FillAll"
|
||||
case NonZero:
|
||||
return "NonZero"
|
||||
case EvenOdd:
|
||||
return "EvenOdd"
|
||||
case FillRuleFillAll:
|
||||
return "FillRuleFillAll"
|
||||
case FillRuleNonZero:
|
||||
return "FillRuleNonZero"
|
||||
case FillRuleEvenOdd:
|
||||
return "FillRuleEvenOdd"
|
||||
default:
|
||||
return fmt.Sprintf("FillRule(%d)", f)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ type Graphics interface {
|
||||
NewShader(program *shaderir.Program) (Shader, error)
|
||||
|
||||
// DrawTriangles draws an image onto another image with the given parameters.
|
||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error
|
||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderSrcImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error
|
||||
}
|
||||
|
||||
type Resetter interface {
|
||||
@@ -95,3 +95,11 @@ type Shader interface {
|
||||
}
|
||||
|
||||
type ShaderID int
|
||||
|
||||
type ColorSpace int
|
||||
|
||||
const (
|
||||
ColorSpaceDefault ColorSpace = iota
|
||||
ColorSpaceSRGB
|
||||
ColorSpaceDisplayP3
|
||||
)
|
||||
|
||||
Generated
Vendored
+150
-46
@@ -29,13 +29,46 @@ import (
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
var (
|
||||
class_CAMetalLayer = objc.GetClass("CAMetalLayer")
|
||||
class_CAMetalDisplayLink = objc.GetClass("CAMetalDisplayLink")
|
||||
class_CAMetalDisplayLinkUpdate = objc.GetClass("CAMetalDisplayLinkUpdate")
|
||||
)
|
||||
|
||||
var (
|
||||
sel_pixelFormat = objc.RegisterName("pixelFormat")
|
||||
sel_setDevice = objc.RegisterName("setDevice:")
|
||||
sel_setOpaque = objc.RegisterName("setOpaque:")
|
||||
sel_setPixelFormat = objc.RegisterName("setPixelFormat:")
|
||||
sel_new = objc.RegisterName("new")
|
||||
sel_setColorspace = objc.RegisterName("setColorspace:")
|
||||
sel_setMaximumDrawableCount = objc.RegisterName("setMaximumDrawableCount:")
|
||||
sel_setDisplaySyncEnabled = objc.RegisterName("setDisplaySyncEnabled:")
|
||||
sel_setDrawableSize = objc.RegisterName("setDrawableSize:")
|
||||
sel_nextDrawable = objc.RegisterName("nextDrawable")
|
||||
sel_presentsWithTransaction = objc.RegisterName("presentsWithTransaction")
|
||||
sel_setPresentsWithTransaction = objc.RegisterName("setPresentsWithTransaction:")
|
||||
sel_setFramebufferOnly = objc.RegisterName("setFramebufferOnly:")
|
||||
sel_texture = objc.RegisterName("texture")
|
||||
sel_present = objc.RegisterName("present")
|
||||
sel_alloc = objc.RegisterName("alloc")
|
||||
sel_initWithMetalLayer = objc.RegisterName("initWithMetalLayer:")
|
||||
sel_setDelegate = objc.RegisterName("setDelegate:")
|
||||
sel_addToOneLoopForMode = objc.RegisterName("addToRunLoop:forMode:")
|
||||
sel_removeFromRunLoopForMode = objc.RegisterName("removeFromRunLoop:forMode:")
|
||||
sel_setPaused = objc.RegisterName("setPaused:")
|
||||
sel_drawable = objc.RegisterName("drawable")
|
||||
sel_release = objc.RegisterName("release")
|
||||
)
|
||||
|
||||
// Layer is an object that manages image-based content and
|
||||
// allows you to perform animations on that content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/calayer.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/calayer?language=objc.
|
||||
type Layer interface {
|
||||
// Layer returns the underlying CALayer * pointer.
|
||||
Layer() unsafe.Pointer
|
||||
@@ -43,15 +76,15 @@ type Layer interface {
|
||||
|
||||
// MetalLayer is a Core Animation Metal layer, a layer that manages a pool of Metal drawables.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer?language=objc.
|
||||
type MetalLayer struct {
|
||||
metalLayer objc.ID
|
||||
}
|
||||
|
||||
// MakeMetalLayer creates a new Core Animation Metal layer.
|
||||
// NewMetalLayer creates a new Core Animation Metal layer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
|
||||
func MakeMetalLayer() (MetalLayer, error) {
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer?language=objc.
|
||||
func NewMetalLayer(colorSpace graphicsdriver.ColorSpace) (MetalLayer, error) {
|
||||
coreGraphics, err := purego.Dlopen("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
@@ -67,15 +100,32 @@ func MakeMetalLayer() (MetalLayer, error) {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
kCGColorSpaceDisplayP3, err := purego.Dlsym(coreGraphics, "kCGColorSpaceDisplayP3")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
var colorSpaceSym uintptr
|
||||
switch colorSpace {
|
||||
case graphicsdriver.ColorSpaceSRGB:
|
||||
kCGColorSpaceSRGB, err := purego.Dlsym(coreGraphics, "kCGColorSpaceSRGB")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
colorSpaceSym = kCGColorSpaceSRGB
|
||||
default:
|
||||
fallthrough
|
||||
case graphicsdriver.ColorSpaceDisplayP3:
|
||||
kCGColorSpaceDisplayP3, err := purego.Dlsym(coreGraphics, "kCGColorSpaceDisplayP3")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
colorSpaceSym = kCGColorSpaceDisplayP3
|
||||
}
|
||||
|
||||
layer := objc.ID(objc.GetClass("CAMetalLayer")).Send(objc.RegisterName("new"))
|
||||
layer := objc.ID(class_CAMetalLayer).Send(sel_new)
|
||||
// setColorspace: is available from iOS 13.0?
|
||||
// https://github.com/hajimehoshi/ebiten/commit/3af351a2aa31e30affd433429c42130015b302f3
|
||||
// TODO: Enable this on iOS as well.
|
||||
if runtime.GOOS != "ios" {
|
||||
colorspace, _, _ := purego.SyscallN(cgColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&kCGColorSpaceDisplayP3))) // Dlsym returns pointer to symbol so dereference it
|
||||
layer.Send(objc.RegisterName("setColorspace:"), colorspace)
|
||||
// Dlsym returns pointer to symbol so dereference it.
|
||||
colorspace, _, _ := purego.SyscallN(cgColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&colorSpaceSym)))
|
||||
layer.Send(sel_setColorspace, colorspace)
|
||||
purego.SyscallN(cgColorSpaceRelease, colorspace)
|
||||
}
|
||||
return MetalLayer{layer}, nil
|
||||
@@ -88,21 +138,21 @@ func (ml MetalLayer) Layer() unsafe.Pointer {
|
||||
|
||||
// PixelFormat returns the pixel format of textures for rendering layer content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat?language=objc.
|
||||
func (ml MetalLayer) PixelFormat() mtl.PixelFormat {
|
||||
return mtl.PixelFormat(ml.metalLayer.Send(objc.RegisterName("pixelFormat")))
|
||||
return mtl.PixelFormat(ml.metalLayer.Send(sel_pixelFormat))
|
||||
}
|
||||
|
||||
// SetDevice sets the Metal device responsible for the layer's drawable resources.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device?language=objc.
|
||||
func (ml MetalLayer) SetDevice(device mtl.Device) {
|
||||
ml.metalLayer.Send(objc.RegisterName("setDevice:"), uintptr(device.Device()))
|
||||
ml.metalLayer.Send(sel_setDevice, uintptr(device.Device()))
|
||||
}
|
||||
|
||||
// SetOpaque a Boolean value indicating whether the layer contains completely opaque content.
|
||||
func (ml MetalLayer) SetOpaque(opaque bool) {
|
||||
ml.metalLayer.Send(objc.RegisterName("setOpaque:"), opaque)
|
||||
ml.metalLayer.Send(sel_setOpaque, opaque)
|
||||
}
|
||||
|
||||
// SetPixelFormat controls the pixel format of textures for rendering layer content.
|
||||
@@ -111,14 +161,14 @@ func (ml MetalLayer) SetOpaque(opaque bool) {
|
||||
// PixelFormatRGBA16Float, PixelFormatBGRA10XR, or PixelFormatBGRA10XRSRGB.
|
||||
// SetPixelFormat panics for other values.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat?language=objc.
|
||||
func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) {
|
||||
switch pf {
|
||||
case mtl.PixelFormatRGBA8UNorm, mtl.PixelFormatRGBA8UNormSRGB, mtl.PixelFormatBGRA8UNorm, mtl.PixelFormatBGRA8UNormSRGB, mtl.PixelFormatStencil8:
|
||||
default:
|
||||
panic(errors.New(fmt.Sprintf("invalid pixel format %d", pf)))
|
||||
panic(fmt.Sprintf("ca: invalid pixel format %d", pf))
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("setPixelFormat:"), uint(pf))
|
||||
ml.metalLayer.Send(sel_setPixelFormat, uint(pf))
|
||||
}
|
||||
|
||||
// SetMaximumDrawableCount controls the number of Metal drawables in the resource pool
|
||||
@@ -126,44 +176,37 @@ func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) {
|
||||
//
|
||||
// It can set to 2 or 3 only. SetMaximumDrawableCount panics for other values.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount?language=objc.
|
||||
func (ml MetalLayer) SetMaximumDrawableCount(count int) {
|
||||
if count < 2 || count > 3 {
|
||||
panic(errors.New(fmt.Sprintf("failed trying to set maximumDrawableCount to %d outside of the valid range of [2, 3]", count)))
|
||||
panic(fmt.Sprintf("ca: failed trying to set maximumDrawableCount to %d outside of the valid range of [2, 3]", count))
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("setMaximumDrawableCount:"), count)
|
||||
ml.metalLayer.Send(sel_setMaximumDrawableCount, count)
|
||||
}
|
||||
|
||||
// SetDisplaySyncEnabled controls whether the Metal layer and its drawables
|
||||
// are synchronized with the display's refresh rate.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2887087-displaysyncenabled.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2887087-displaysyncenabled?language=objc.
|
||||
func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) {
|
||||
if runtime.GOOS == "ios" {
|
||||
return
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("setDisplaySyncEnabled:"), enabled)
|
||||
ml.metalLayer.Send(sel_setDisplaySyncEnabled, enabled)
|
||||
}
|
||||
|
||||
// SetDrawableSize sets the size, in pixels, of textures for rendering layer content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize?language=objc.
|
||||
func (ml MetalLayer) SetDrawableSize(width, height int) {
|
||||
// TODO: once objc supports calling functions with struct arguments replace this with just a ID.Send call
|
||||
var sel_setDrawableSize = objc.RegisterName("setDrawableSize:")
|
||||
sig := cocoa.NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(objc.GetClass("CAMetalLayer")), sel_setDrawableSize)
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetTarget(ml.metalLayer)
|
||||
inv.SetSelector(sel_setDrawableSize)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&cocoa.CGSize{Width: cocoa.CGFloat(width), Height: cocoa.CGFloat(height)}), 2)
|
||||
inv.Invoke()
|
||||
ml.metalLayer.Send(sel_setDrawableSize, cocoa.CGSize{Width: cocoa.CGFloat(width), Height: cocoa.CGFloat(height)})
|
||||
}
|
||||
|
||||
// NextDrawable returns a Metal drawable.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable?language=objc.
|
||||
func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
|
||||
md := ml.metalLayer.Send(objc.RegisterName("nextDrawable"))
|
||||
md := ml.metalLayer.Send(sel_nextDrawable)
|
||||
if md == 0 {
|
||||
return MetalDrawable{}, errors.New("nextDrawable returned nil")
|
||||
}
|
||||
@@ -172,28 +215,28 @@ func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
|
||||
|
||||
// PresentsWithTransaction returns a Boolean value that determines whether the layer presents its content using a Core Animation transaction.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction?language=objc
|
||||
func (ml MetalLayer) PresentsWithTransaction() bool {
|
||||
return ml.metalLayer.Send(objc.RegisterName("presentsWithTransaction")) != 0
|
||||
return ml.metalLayer.Send(sel_presentsWithTransaction) != 0
|
||||
}
|
||||
|
||||
// SetPresentsWithTransaction sets a Boolean value that determines whether the layer presents its content using a Core Animation transaction.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction?language=objc
|
||||
func (ml MetalLayer) SetPresentsWithTransaction(presentsWithTransaction bool) {
|
||||
ml.metalLayer.Send(objc.RegisterName("setPresentsWithTransaction:"), presentsWithTransaction)
|
||||
ml.metalLayer.Send(sel_setPresentsWithTransaction, presentsWithTransaction)
|
||||
}
|
||||
|
||||
// SetFramebufferOnly sets a Boolean value that determines whether the layer’s textures are used only for rendering.
|
||||
//
|
||||
// https://developer.apple.com/documentation/quartzcore/cametallayer/1478168-framebufferonly
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478168-framebufferonly?language=objc
|
||||
func (ml MetalLayer) SetFramebufferOnly(framebufferOnly bool) {
|
||||
ml.metalLayer.Send(objc.RegisterName("setFramebufferOnly:"), framebufferOnly)
|
||||
ml.metalLayer.Send(sel_setFramebufferOnly, framebufferOnly)
|
||||
}
|
||||
|
||||
// MetalDrawable is a displayable resource that can be rendered or written to by Metal.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable?language=objc.
|
||||
type MetalDrawable struct {
|
||||
metalDrawable objc.ID
|
||||
}
|
||||
@@ -205,14 +248,75 @@ func (md MetalDrawable) Drawable() unsafe.Pointer {
|
||||
|
||||
// Texture returns a Metal texture object representing the drawable object's content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture.
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture?language=objc.
|
||||
func (md MetalDrawable) Texture() mtl.Texture {
|
||||
return mtl.NewTexture(md.metalDrawable.Send(objc.RegisterName("texture")))
|
||||
return mtl.NewTexture(md.metalDrawable.Send(sel_texture))
|
||||
}
|
||||
|
||||
// Present presents the drawable onscreen as soon as possible.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldrawable/1470284-present.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldrawable/1470284-present?language=objc.
|
||||
func (md MetalDrawable) Present() {
|
||||
md.metalDrawable.Send(objc.RegisterName("present"))
|
||||
md.metalDrawable.Send(sel_present)
|
||||
}
|
||||
|
||||
// MetalDisplayLink is a class your Metal app uses to register for callbacks to synchronize its animations for a display.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink?language=objc
|
||||
type MetalDisplayLink struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
// SetDelegate sets an instance of a type your app implements that responds to the system’s callbacks.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/delegate?language=objc
|
||||
func (m MetalDisplayLink) SetDelegate(delegate objc.ID) {
|
||||
m.Send(sel_setDelegate, delegate)
|
||||
}
|
||||
|
||||
// AddToRunLoop registers the display link with a run loop.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/add(to:formode:)?language=objc
|
||||
func (m MetalDisplayLink) AddToRunLoop(runLoop cocoa.NSRunLoop, mode cocoa.NSRunLoopMode) {
|
||||
m.Send(sel_addToOneLoopForMode, runLoop, mode)
|
||||
}
|
||||
|
||||
// RemoveFromRunLoop removes a mode’s display link from a run loop.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/remove(from:formode:)?language=objc
|
||||
func (m MetalDisplayLink) RemoveFromRunLoop(runLoop cocoa.NSRunLoop, mode cocoa.NSRunLoopMode) {
|
||||
m.Send(sel_removeFromRunLoopForMode, runLoop, mode)
|
||||
}
|
||||
|
||||
// SetPaused sets a Boolean value that indicates whether the system suspends the display link’s notifications to the target.
|
||||
//
|
||||
// https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/ispaused?language=objc
|
||||
func (m MetalDisplayLink) SetPaused(paused bool) {
|
||||
m.Send(sel_setPaused, paused)
|
||||
}
|
||||
|
||||
func (m MetalDisplayLink) Release() {
|
||||
m.Send(sel_release)
|
||||
}
|
||||
|
||||
// NewMetalDisplayLink creates a display link for Metal from a Core Animation layer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/init(metallayer:)?language=objc
|
||||
func NewMetalDisplayLink(metalLayer MetalLayer) MetalDisplayLink {
|
||||
displayLink := objc.ID(class_CAMetalDisplayLink).Send(sel_alloc).Send(sel_initWithMetalLayer, metalLayer.metalLayer)
|
||||
return MetalDisplayLink{displayLink}
|
||||
}
|
||||
|
||||
// MetalDisplayLinkUpdate stores information about a single update from a Metal display link instance.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/update?language=objc
|
||||
type MetalDisplayLinkUpdate struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
// Drawable returns the Metal drawable your app uses to render the next frame.
|
||||
//
|
||||
// https://developer.apple.com/documentation/quartzcore/cametaldisplaylink/update/drawable?language=objc
|
||||
func (m MetalDisplayLinkUpdate) Drawable() MetalDrawable {
|
||||
return MetalDrawable{m.Send(sel_drawable)}
|
||||
}
|
||||
|
||||
Generated
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
// Copyright 2025 The Ebitengine Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build darwin && !ios
|
||||
|
||||
package metal
|
||||
|
||||
// #cgo CFLAGS: -x objective-c
|
||||
//
|
||||
// #include <Foundation/Foundation.h>
|
||||
// #include <CoreVideo/CVDisplayLink.h>
|
||||
// #if __has_include(<QuartzCore/CAMetalLayer.h>)
|
||||
// #include <QuartzCore/CAMetalLayer.h>
|
||||
// #endif
|
||||
//
|
||||
// #cgo noescape isCAMetalDisplayLinkAvailable
|
||||
// #cgo nocallback isCAMetalDisplayLinkAvailable
|
||||
// static bool isCAMetalDisplayLinkAvailable() {
|
||||
// // TODO: Use PureGo if returning a struct is supported (ebitengine/purego#225).
|
||||
// // As operatingSystemVersion returns a struct, this cannot be written with PureGo.
|
||||
// NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
// if (version.majorVersion >= 14) {
|
||||
// // Also check if the CAMetalDisplayLink class exists
|
||||
// return NSClassFromString(@"CAMetalDisplayLink") != nil;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// int ebitengine_DisplayLinkOutputCallback(CVDisplayLinkRef displayLinkRef, CVTimeStamp* inNow, CVTimeStamp* inOutputTime, uint64_t flagsIn, uint64_t* flagsOut, void* displayLinkContext);
|
||||
import "C"
|
||||
import (
|
||||
"log/slog"
|
||||
"runtime"
|
||||
"runtime/cgo"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
|
||||
)
|
||||
|
||||
func (v *view) initDisplayLink() error {
|
||||
if C.isCAMetalDisplayLinkAvailable() {
|
||||
if err := v.initCAMetalDisplayLink(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := v.initCADisplayLink(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var class_EbitengineCAMetalDisplayLinkDelegate objc.Class
|
||||
|
||||
func (v *view) initCAMetalDisplayLink() error {
|
||||
v.drawableCh = make(chan ca.MetalDrawable)
|
||||
v.drawableDoneCh = make(chan struct{})
|
||||
v.metalDisplayLinkRunLoop = createThreadWithRunLoop()
|
||||
|
||||
c, err := objc.RegisterClass(
|
||||
"EbitengineCAMetalDisplayLinkDelegate",
|
||||
objc.GetClass("NSObject"),
|
||||
[]*objc.Protocol{objc.GetProtocol("CAMetalDisplayLinkDelegate")},
|
||||
nil,
|
||||
[]objc.MethodDef{
|
||||
{
|
||||
Cmd: objc.RegisterName("metalDisplayLink:needsUpdate:"),
|
||||
Fn: func(id objc.ID, cmd objc.SEL, metalDisplayLink objc.ID, needsUpdate objc.ID) {
|
||||
// There is a case where this callback is invoked from the main run loop (#3353).
|
||||
// This is very mysterious, but this causes a deadlock.
|
||||
// As a workaround, return this immediately when the current run loop is the main run loop.
|
||||
if cocoa.NSRunLoop_currentRunLoop() == cocoa.NSRunLoop_mainRunLoop() {
|
||||
slog.Debug("metal: metalDisplayLink:needsUpdate: is unexpectedly called from the main run loop")
|
||||
return
|
||||
}
|
||||
drawable := ca.MetalDisplayLinkUpdate{ID: needsUpdate}.Drawable()
|
||||
if drawable == (ca.MetalDrawable{}) {
|
||||
return
|
||||
}
|
||||
v.drawableCh <- drawable
|
||||
<-v.drawableDoneCh
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
class_EbitengineCAMetalDisplayLinkDelegate = c
|
||||
|
||||
v.createCAMetalDisplayLink()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *view) createCAMetalDisplayLink() {
|
||||
ch := make(chan uintptr)
|
||||
v.metalDisplayLinkRunLoop.PerformBlock(objc.NewBlock(func(block objc.Block) {
|
||||
dl := ca.NewMetalDisplayLink(v.ml)
|
||||
dl.SetDelegate(objc.ID(class_EbitengineCAMetalDisplayLinkDelegate).Send(objc.RegisterName("new")))
|
||||
dl.AddToRunLoop(v.metalDisplayLinkRunLoop, cocoa.NSDefaultRunLoopMode)
|
||||
dl.SetPaused(false)
|
||||
ch <- uintptr(dl.ID)
|
||||
close(ch)
|
||||
}))
|
||||
v.metalDisplayLink = <-ch
|
||||
}
|
||||
|
||||
func createThreadWithRunLoop() cocoa.NSRunLoop {
|
||||
ch := make(chan cocoa.NSRunLoop)
|
||||
go func() {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
runLoop := cocoa.NSRunLoop_currentRunLoop()
|
||||
ch <- runLoop
|
||||
close(ch)
|
||||
|
||||
// Add a dummy mach port to keep alive.
|
||||
port := cocoa.NSMachPort_port()
|
||||
runLoop.AddPort(port, cocoa.NSRunLoopCommonModes)
|
||||
|
||||
runLoop.Run()
|
||||
}()
|
||||
|
||||
runLoop := <-ch
|
||||
if runLoop.ID == 0 {
|
||||
panic("metal: runLoop must be initialized")
|
||||
}
|
||||
return runLoop
|
||||
}
|
||||
|
||||
func (v *view) initCADisplayLink() error {
|
||||
v.fence = newFence()
|
||||
|
||||
// TODO: CVDisplayLink APIs are deprecated in macOS 10.15 and later.
|
||||
// Use new APIs like NSView.displayLink(target:selector:).
|
||||
var displayLinkRef C.CVDisplayLinkRef
|
||||
if ret := C.CVDisplayLinkCreateWithActiveCGDisplays(&displayLinkRef); ret != kCVReturnSuccess {
|
||||
// Failed to get the display link, so proceed without it.
|
||||
return nil
|
||||
}
|
||||
v.handleToSelf = cgo.NewHandle(v)
|
||||
C.CVDisplayLinkSetOutputCallback(displayLinkRef, C.CVDisplayLinkOutputCallback(C.ebitengine_DisplayLinkOutputCallback), unsafe.Pointer(&v.handleToSelf))
|
||||
C.CVDisplayLinkStart(displayLinkRef)
|
||||
|
||||
v.caDisplayLink = uintptr(displayLinkRef)
|
||||
return nil
|
||||
}
|
||||
|
||||
//export ebitengine_DisplayLinkOutputCallback
|
||||
func ebitengine_DisplayLinkOutputCallback(displayLinkRef C.CVDisplayLinkRef, inNow, inOutputTime *C.CVTimeStamp, flagsIn C.uint64_t, flagsOut *C.uint64_t, displayLinkContext unsafe.Pointer) C.int {
|
||||
cgoHandle := (*cgo.Handle)(displayLinkContext)
|
||||
view := cgoHandle.Value().(*view)
|
||||
view.fence.advance()
|
||||
return 0
|
||||
}
|
||||
|
||||
func (v *view) nextDrawable() ca.MetalDrawable {
|
||||
if v.metalDisplayLink != 0 {
|
||||
const wait = 100 * time.Millisecond
|
||||
if v.drawableTimer == nil {
|
||||
v.drawableTimer = time.NewTimer(wait)
|
||||
} else {
|
||||
v.drawableTimer.Reset(wait)
|
||||
}
|
||||
defer v.drawableTimer.Stop()
|
||||
select {
|
||||
case d := <-v.drawableCh:
|
||||
return d
|
||||
case <-v.drawableTimer.C:
|
||||
// This happens when the main thread needs to execute the notification observer callback,
|
||||
// or when the appliation goes to full screen (#3354).
|
||||
return ca.MetalDrawable{}
|
||||
}
|
||||
}
|
||||
|
||||
v.waitForDisplayLinkOutputCallback()
|
||||
|
||||
d, err := v.ml.NextDrawable()
|
||||
if err != nil {
|
||||
// Drawable is nil. This can happen at the initial state. Let's wait and see.
|
||||
return ca.MetalDrawable{}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (v *view) finishDrawableUsage() {
|
||||
if v.metalDisplayLink != 0 {
|
||||
v.drawableDoneCh <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+246
-137
@@ -32,9 +32,13 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
var sel_supportsFamily = objc.RegisterName("supportsFamily:")
|
||||
|
||||
type Graphics struct {
|
||||
view view
|
||||
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
|
||||
cq mtl.CommandQueue
|
||||
cb mtl.CommandBuffer
|
||||
rce mtl.RenderCommandEncoder
|
||||
@@ -42,7 +46,15 @@ type Graphics struct {
|
||||
|
||||
screenDrawable ca.MetalDrawable
|
||||
|
||||
buffers map[mtl.CommandBuffer][]mtl.Buffer
|
||||
// frame is the current frame number.
|
||||
// frame is incremented when the screen is presented.
|
||||
frame int64
|
||||
|
||||
// frameToCB maps a frame number to command buffers used in the frame.
|
||||
// frameToCB keeps command buffers not to be released until the command buffers are completed.
|
||||
frameToCB map[int64][]mtl.CommandBuffer
|
||||
|
||||
buffers map[int64][]mtl.Buffer
|
||||
unusedBuffers map[mtl.Buffer]struct{}
|
||||
|
||||
lastDst *Image
|
||||
@@ -90,7 +102,7 @@ func init() {
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for Metal.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
func NewGraphics(colorSpace graphicsdriver.ColorSpace) (graphicsdriver.Graphics, error) {
|
||||
// On old mac devices like iMac 2011, Metal is not supported (#779).
|
||||
// TODO: Is there a better way to check whether Metal is available or not?
|
||||
// It seems OK to call MTLCreateSystemDefaultDevice multiple times, so this should be fine.
|
||||
@@ -98,12 +110,14 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
return nil, fmt.Errorf("metal: mtl.CreateSystemDefaultDevice failed: %w", systemDefaultDeviceErr)
|
||||
}
|
||||
|
||||
g := &Graphics{}
|
||||
g := &Graphics{
|
||||
colorSpace: colorSpace,
|
||||
}
|
||||
|
||||
if runtime.GOOS != "ios" {
|
||||
// Initializing a Metal device and a layer must be done in the main thread on macOS.
|
||||
// Note that this assumes NewGraphics is called on the main thread on desktops.
|
||||
if err := g.view.initialize(systemDefaultDevice); err != nil {
|
||||
if err := g.view.initialize(systemDefaultDevice, colorSpace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -118,10 +132,12 @@ func (g *Graphics) Begin() error {
|
||||
}
|
||||
|
||||
func (g *Graphics) End(present bool) error {
|
||||
g.flushIfNeeded(present)
|
||||
g.screenDrawable = ca.MetalDrawable{}
|
||||
g.flushCommandBufferIfNeeded(present)
|
||||
g.pool.Release()
|
||||
g.pool.ID = 0
|
||||
if present {
|
||||
g.frame++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -149,21 +165,30 @@ func pow2(x uintptr) uintptr {
|
||||
}
|
||||
|
||||
func (g *Graphics) gcBuffers() {
|
||||
for cb, bs := range g.buffers {
|
||||
// If the command buffer still lives, the buffer must not be updated.
|
||||
// TODO: Handle an error?
|
||||
if cb.Status() != mtl.CommandBufferStatusCompleted {
|
||||
loop:
|
||||
for frame, bs := range g.buffers {
|
||||
if frame == g.frame {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if all command buffers for the frame are completed.
|
||||
for _, cb := range g.frameToCB[frame] {
|
||||
if cb.Status() != mtl.CommandBufferStatusCompleted {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
for _, cb := range g.frameToCB[frame] {
|
||||
cb.Release()
|
||||
}
|
||||
delete(g.frameToCB, frame)
|
||||
|
||||
for _, b := range bs {
|
||||
if g.unusedBuffers == nil {
|
||||
g.unusedBuffers = map[mtl.Buffer]struct{}{}
|
||||
}
|
||||
g.unusedBuffers[b] = struct{}{}
|
||||
}
|
||||
delete(g.buffers, cb)
|
||||
cb.Release()
|
||||
delete(g.buffers, frame)
|
||||
}
|
||||
|
||||
const maxUnusedBuffers = 10
|
||||
@@ -182,10 +207,20 @@ func (g *Graphics) gcBuffers() {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) availableBuffer(length uintptr) mtl.Buffer {
|
||||
if g.cb == (mtl.CommandBuffer{}) {
|
||||
g.cb = g.cq.MakeCommandBuffer()
|
||||
func (g *Graphics) ensureCommandBuffer() {
|
||||
if g.cb != (mtl.CommandBuffer{}) {
|
||||
return
|
||||
}
|
||||
g.cb = g.cq.CommandBuffer()
|
||||
if g.frameToCB == nil {
|
||||
g.frameToCB = map[int64][]mtl.CommandBuffer{}
|
||||
}
|
||||
g.frameToCB[g.frame] = append(g.frameToCB[g.frame], g.cb)
|
||||
g.cb.Retain()
|
||||
}
|
||||
|
||||
func (g *Graphics) availableBuffer(length uintptr) mtl.Buffer {
|
||||
g.ensureCommandBuffer()
|
||||
|
||||
var newBuf mtl.Buffer
|
||||
for b := range g.unusedBuffers {
|
||||
@@ -197,16 +232,13 @@ func (g *Graphics) availableBuffer(length uintptr) mtl.Buffer {
|
||||
}
|
||||
|
||||
if newBuf == (mtl.Buffer{}) {
|
||||
newBuf = g.view.getMTLDevice().MakeBufferWithLength(pow2(length), resourceStorageMode)
|
||||
newBuf = g.view.getMTLDevice().NewBufferWithLength(pow2(length), resourceStorageMode)
|
||||
}
|
||||
|
||||
if g.buffers == nil {
|
||||
g.buffers = map[mtl.CommandBuffer][]mtl.Buffer{}
|
||||
g.buffers = map[int64][]mtl.Buffer{}
|
||||
}
|
||||
if _, ok := g.buffers[g.cb]; !ok {
|
||||
g.cb.Retain()
|
||||
}
|
||||
g.buffers[g.cb] = append(g.buffers[g.cb], newBuf)
|
||||
g.buffers[g.frame] = append(g.buffers[g.frame], newBuf)
|
||||
return newBuf
|
||||
}
|
||||
|
||||
@@ -223,21 +255,21 @@ func (g *Graphics) SetVertices(vertices []float32, indices []uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) flushIfNeeded(present bool) {
|
||||
if g.cb == (mtl.CommandBuffer{}) && !present {
|
||||
func (g *Graphics) flushCommandBufferIfNeeded(present bool) {
|
||||
if g.cb == (mtl.CommandBuffer{}) {
|
||||
if g.rce != (mtl.RenderCommandEncoder{}) {
|
||||
panic("metal: render command encoder must be empty if command buffer is empty")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
g.flushRenderCommandEncoderIfNeeded()
|
||||
|
||||
if present {
|
||||
// This check is necessary when skipping to render the screen (SetScreenClearedEveryFrame(false)).
|
||||
if g.screenDrawable == (ca.MetalDrawable{}) && g.cb != (mtl.CommandBuffer{}) {
|
||||
g.screenDrawable = g.view.nextDrawable()
|
||||
}
|
||||
if g.screenDrawable != (ca.MetalDrawable{}) {
|
||||
g.cb.PresentDrawable(g.screenDrawable)
|
||||
}
|
||||
var presented bool
|
||||
if present && g.screenDrawable != (ca.MetalDrawable{}) {
|
||||
g.cb.PresentDrawable(g.screenDrawable)
|
||||
g.screenDrawable = ca.MetalDrawable{}
|
||||
presented = true
|
||||
}
|
||||
|
||||
g.cb.Commit()
|
||||
@@ -248,6 +280,10 @@ func (g *Graphics) flushIfNeeded(present bool) {
|
||||
g.tmpTextures = g.tmpTextures[:0]
|
||||
|
||||
g.cb = mtl.CommandBuffer{}
|
||||
|
||||
if presented {
|
||||
g.view.finishDrawableUsage()
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) checkSize(width, height int) {
|
||||
@@ -286,7 +322,7 @@ func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
StorageMode: storageMode,
|
||||
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
t := g.view.getMTLDevice().MakeTexture(td)
|
||||
t := g.view.getMTLDevice().NewTextureWithDescriptor(td)
|
||||
i := &Image{
|
||||
id: g.genNextImageID(),
|
||||
graphics: g,
|
||||
@@ -388,16 +424,17 @@ func (g *Graphics) Initialize() error {
|
||||
|
||||
if runtime.GOOS == "ios" {
|
||||
// Initializing a Metal device and a layer must be done in the render thread on iOS.
|
||||
if err := g.view.initialize(systemDefaultDevice); err != nil {
|
||||
if err := g.view.initialize(systemDefaultDevice, g.colorSpace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if g.transparent {
|
||||
g.view.ml.SetOpaque(false)
|
||||
}
|
||||
// The default value is false [1], but transparinting doesn't work without calling this.
|
||||
// To avoid confusion, let's call this explicitly.
|
||||
// [1] https://developer.apple.com/documentation/quartzcore/calayer/isopaque?language=objc
|
||||
g.view.ml.SetOpaque(!g.transparent)
|
||||
|
||||
// The stencil reference value is always 0 (default).
|
||||
g.dsss[noStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
g.dsss[noStencil] = g.view.getMTLDevice().NewDepthStencilStateWithDescriptor(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
@@ -411,7 +448,7 @@ func (g *Graphics) Initialize() error {
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[incrementStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
g.dsss[incrementStencil] = g.view.getMTLDevice().NewDepthStencilStateWithDescriptor(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
@@ -425,7 +462,7 @@ func (g *Graphics) Initialize() error {
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[invertStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
g.dsss[invertStencil] = g.view.getMTLDevice().NewDepthStencilStateWithDescriptor(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
@@ -439,7 +476,7 @@ func (g *Graphics) Initialize() error {
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[drawWithStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
g.dsss[drawWithStencil] = g.view.getMTLDevice().NewDepthStencilStateWithDescriptor(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
@@ -454,7 +491,7 @@ func (g *Graphics) Initialize() error {
|
||||
},
|
||||
})
|
||||
|
||||
g.cq = g.view.getMTLDevice().MakeCommandQueue()
|
||||
g.cq = g.view.getMTLDevice().NewCommandQueue()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -467,11 +504,18 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
|
||||
g.lastDst = nil
|
||||
}
|
||||
|
||||
func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs [graphics.ShaderImageCount]*Image, indexOffset int, shader *Shader, uniforms [][]uint32, blend graphicsdriver.Blend, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs [graphics.ShaderSrcImageCount]*Image, indexOffset int, shader *Shader, uniforms []uint32, blend graphicsdriver.Blend, fillRule graphicsdriver.FillRule) error {
|
||||
// In order to create a separate command buffer for the screen, flush the current command buffer.
|
||||
// It's because a drawable will not be released as long as the CommandBuffer referencing it is alive,
|
||||
// it is more efficient to separate CommandBuffers that use the drawable from those that do not.
|
||||
if (g.lastDst != nil && g.lastDst.screen) != dst.screen {
|
||||
g.flushCommandBufferIfNeeded(false)
|
||||
}
|
||||
|
||||
// When preparing a stencil buffer, flush the current render command encoder
|
||||
// to make sure the stencil buffer is cleared when loading.
|
||||
// TODO: What about clearing the stencil buffer by vertices?
|
||||
if g.lastDst != dst || g.lastFillRule != fillRule || fillRule != graphicsdriver.FillAll {
|
||||
if g.lastDst != dst || g.lastFillRule != fillRule || fillRule != graphicsdriver.FillRuleFillAll {
|
||||
g.flushRenderCommandEncoderIfNeeded()
|
||||
}
|
||||
g.lastDst = dst
|
||||
@@ -497,17 +541,15 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
||||
rpd.ColorAttachments[0].Texture = t
|
||||
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
dst.ensureStencil()
|
||||
rpd.StencilAttachment.LoadAction = mtl.LoadActionClear
|
||||
rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare
|
||||
rpd.StencilAttachment.Texture = dst.stencil
|
||||
}
|
||||
|
||||
if g.cb == (mtl.CommandBuffer{}) {
|
||||
g.cb = g.cq.MakeCommandBuffer()
|
||||
}
|
||||
g.rce = g.cb.MakeRenderCommandEncoder(rpd)
|
||||
g.ensureCommandBuffer()
|
||||
g.rce = g.cb.RenderCommandEncoderWithDescriptor(rpd)
|
||||
}
|
||||
|
||||
w, h := dst.internalSize()
|
||||
@@ -521,12 +563,11 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
||||
})
|
||||
g.rce.SetVertexBuffer(g.vb, 0, 0)
|
||||
|
||||
for i, u := range uniforms {
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
g.rce.SetVertexBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
||||
g.rce.SetFragmentBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1)
|
||||
if len(uniforms) > 0 {
|
||||
uniforms := adjustUniformVariablesLayout(shader.ir.Uniforms, uniforms)
|
||||
head := unsafe.SliceData(uniforms)
|
||||
g.rce.SetVertexBytes(unsafe.Pointer(head), unsafe.Sizeof(uniforms[0])*uintptr(len(uniforms)), 1)
|
||||
g.rce.SetFragmentBytes(unsafe.Pointer(head), unsafe.Sizeof(uniforms[0])*uintptr(len(uniforms)), 0)
|
||||
}
|
||||
|
||||
for i, src := range srcs {
|
||||
@@ -544,26 +585,26 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
||||
drawWithStencilRpss mtl.RenderPipelineState
|
||||
)
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
case graphicsdriver.FillRuleFillAll:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
noStencilRpss = s
|
||||
case graphicsdriver.NonZero:
|
||||
case graphicsdriver.FillRuleNonZero:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, incrementStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
incrementStencilRpss = s
|
||||
case graphicsdriver.EvenOdd:
|
||||
case graphicsdriver.FillRuleEvenOdd:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, invertStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
invertStencilRpss = s
|
||||
}
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -580,20 +621,20 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
||||
})
|
||||
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
case graphicsdriver.FillRuleFillAll:
|
||||
g.rce.SetDepthStencilState(g.dsss[noStencil])
|
||||
g.rce.SetRenderPipelineState(noStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
case graphicsdriver.NonZero:
|
||||
case graphicsdriver.FillRuleNonZero:
|
||||
g.rce.SetDepthStencilState(g.dsss[incrementStencil])
|
||||
g.rce.SetRenderPipelineState(incrementStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
case graphicsdriver.EvenOdd:
|
||||
case graphicsdriver.FillRuleEvenOdd:
|
||||
g.rce.SetDepthStencilState(g.dsss[invertStencil])
|
||||
g.rce.SetRenderPipelineState(invertStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
}
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
|
||||
g.rce.SetRenderPipelineState(drawWithStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
@@ -605,7 +646,7 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("metal: shader ID is invalid")
|
||||
}
|
||||
@@ -616,72 +657,12 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
g.view.update()
|
||||
}
|
||||
|
||||
var srcs [graphics.ShaderImageCount]*Image
|
||||
var srcs [graphics.ShaderSrcImageCount]*Image
|
||||
for i, srcID := range srcIDs {
|
||||
srcs[i] = g.images[srcID]
|
||||
}
|
||||
|
||||
uniformVars := make([][]uint32, len(g.shaders[shaderID].ir.Uniforms))
|
||||
|
||||
// Set the additional uniform variables.
|
||||
var idx int
|
||||
for i, t := range g.shaders[shaderID].ir.Uniforms {
|
||||
if i == graphics.ProjectionMatrixUniformVariableIndex {
|
||||
// In Metal, the NDC's Y direction (upward) and the framebuffer's Y direction (downward) don't
|
||||
// match. Then, the Y direction must be inverted.
|
||||
// Invert the sign bits as float32 values.
|
||||
uniforms[idx+1] ^= 1 << 31
|
||||
uniforms[idx+5] ^= 1 << 31
|
||||
uniforms[idx+9] ^= 1 << 31
|
||||
uniforms[idx+13] ^= 1 << 31
|
||||
}
|
||||
|
||||
n := t.Uint32Count()
|
||||
|
||||
switch t.Main {
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
// float3 requires 16-byte alignment (#2463).
|
||||
v1 := make([]uint32, 4)
|
||||
copy(v1[0:3], uniforms[idx:idx+3])
|
||||
uniformVars[i] = v1
|
||||
case shaderir.Mat3:
|
||||
// float3x3 requires 16-byte alignment (#2036).
|
||||
v1 := make([]uint32, 12)
|
||||
copy(v1[0:3], uniforms[idx:idx+3])
|
||||
copy(v1[4:7], uniforms[idx+3:idx+6])
|
||||
copy(v1[8:11], uniforms[idx+6:idx+9])
|
||||
uniformVars[i] = v1
|
||||
case shaderir.Array:
|
||||
switch t.Sub[0].Main {
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
v1 := make([]uint32, t.Length*4)
|
||||
for j := 0; j < t.Length; j++ {
|
||||
offset0 := j * 3
|
||||
offset1 := j * 4
|
||||
copy(v1[offset1:offset1+3], uniforms[idx+offset0:idx+offset0+3])
|
||||
}
|
||||
uniformVars[i] = v1
|
||||
case shaderir.Mat3:
|
||||
v1 := make([]uint32, t.Length*12)
|
||||
for j := 0; j < t.Length; j++ {
|
||||
offset0 := j * 9
|
||||
offset1 := j * 12
|
||||
copy(v1[offset1:offset1+3], uniforms[idx+offset0:idx+offset0+3])
|
||||
copy(v1[offset1+4:offset1+7], uniforms[idx+offset0+3:idx+offset0+6])
|
||||
copy(v1[offset1+8:offset1+11], uniforms[idx+offset0+6:idx+offset0+9])
|
||||
}
|
||||
uniformVars[i] = v1
|
||||
default:
|
||||
uniformVars[i] = uniforms[idx : idx+n]
|
||||
}
|
||||
default:
|
||||
uniformVars[i] = uniforms[idx : idx+n]
|
||||
}
|
||||
|
||||
idx += n
|
||||
}
|
||||
|
||||
if err := g.draw(dst, dstRegions, srcs, indexOffset, g.shaders[shaderID], uniformVars, blend, fillRule); err != nil {
|
||||
if err := g.draw(dst, dstRegions, srcs, indexOffset, g.shaders[shaderID], uniforms, blend, fillRule); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -705,7 +686,7 @@ func (g *Graphics) MaxImageSize() int {
|
||||
|
||||
// supportsFamily is available as of macOS 10.15+ and iOS 13.0+.
|
||||
// https://developer.apple.com/documentation/metal/mtldevice/3143473-supportsfamily
|
||||
if d.RespondsToSelector(objc.RegisterName("supportsFamily:")) {
|
||||
if d.RespondsToSelector(sel_supportsFamily) {
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
g.maxImageSize = 8192
|
||||
switch {
|
||||
@@ -802,16 +783,16 @@ func (i *Image) Dispose() {
|
||||
}
|
||||
|
||||
func (i *Image) syncTexture() {
|
||||
i.graphics.flushRenderCommandEncoderIfNeeded()
|
||||
i.graphics.flushCommandBufferIfNeeded(false)
|
||||
|
||||
// Calling SynchronizeTexture is ignored on iOS (see mtl.m), but it looks like committing BlitCommandEncoder
|
||||
// is necessary (#1337).
|
||||
if i.graphics.cb != (mtl.CommandBuffer{}) {
|
||||
panic("metal: command buffer must be empty at syncTexture: flushIfNeeded is not called yet?")
|
||||
panic("metal: command buffer must be empty at syncTexture")
|
||||
}
|
||||
|
||||
cb := i.graphics.cq.MakeCommandBuffer()
|
||||
bce := cb.MakeBlitCommandEncoder()
|
||||
cb := i.graphics.cq.CommandBuffer()
|
||||
bce := cb.BlitCommandEncoder()
|
||||
bce.SynchronizeTexture(i.texture, 0, 0)
|
||||
bce.EndEncoding()
|
||||
|
||||
@@ -821,7 +802,6 @@ func (i *Image) syncTexture() {
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
i.graphics.flushIfNeeded(false)
|
||||
i.syncTexture()
|
||||
|
||||
for _, arg := range args {
|
||||
@@ -859,7 +839,7 @@ func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
StorageMode: storageMode,
|
||||
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
t := g.view.getMTLDevice().MakeTexture(td)
|
||||
t := g.view.getMTLDevice().NewTextureWithDescriptor(td)
|
||||
g.tmpTextures = append(g.tmpTextures, t)
|
||||
|
||||
for _, a := range args {
|
||||
@@ -869,10 +849,8 @@ func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
}, 0, unsafe.Pointer(&a.Pixels[0]), 4*a.Region.Dx())
|
||||
}
|
||||
|
||||
if g.cb == (mtl.CommandBuffer{}) {
|
||||
g.cb = i.graphics.cq.MakeCommandBuffer()
|
||||
}
|
||||
bce := g.cb.MakeBlitCommandEncoder()
|
||||
g.ensureCommandBuffer()
|
||||
bce := g.cb.BlitCommandEncoder()
|
||||
for _, a := range args {
|
||||
so := mtl.Origin{X: a.Region.Min.X - region.Min.X, Y: a.Region.Min.Y - region.Min.Y, Z: 0}
|
||||
ss := mtl.Size{Width: a.Region.Dx(), Height: a.Region.Dy(), Depth: 1}
|
||||
@@ -896,6 +874,9 @@ func (i *Image) mtlTexture() mtl.Texture {
|
||||
// After nextDrawable, it is expected some command buffers are completed.
|
||||
g.gcBuffers()
|
||||
}
|
||||
if g.screenDrawable == (ca.MetalDrawable{}) {
|
||||
return mtl.Texture{}
|
||||
}
|
||||
return g.screenDrawable.Texture()
|
||||
}
|
||||
return i.texture
|
||||
@@ -914,5 +895,133 @@ func (i *Image) ensureStencil() {
|
||||
StorageMode: mtl.StorageModePrivate,
|
||||
Usage: mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
i.stencil = i.graphics.view.getMTLDevice().MakeTexture(td)
|
||||
i.stencil = i.graphics.view.getMTLDevice().NewTextureWithDescriptor(td)
|
||||
}
|
||||
|
||||
// adjustUniformVariablesLayout returns adjusted uniform variables to match the Metal's memory layout.
|
||||
func adjustUniformVariablesLayout(uniformTypes []shaderir.Type, uniforms []uint32) []uint32 {
|
||||
// Each type's alignment is defined by the specification.
|
||||
// See https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
|
||||
|
||||
var values []uint32
|
||||
fillZerosToFitAlignment := func(values []uint32, align int) []uint32 {
|
||||
if len(values) == 0 {
|
||||
return values
|
||||
}
|
||||
n0 := len(values)
|
||||
n1 := ((len(values)-1)/align + 1) * align
|
||||
if n0 == n1 {
|
||||
return values
|
||||
}
|
||||
return append(values, make([]uint32, n1-n0)...)
|
||||
}
|
||||
|
||||
var idx int
|
||||
var byteAlign int
|
||||
for i, typ := range uniformTypes {
|
||||
n := typ.DwordCount()
|
||||
switch typ.Main {
|
||||
case shaderir.Bool:
|
||||
if byteAlign == 0 {
|
||||
values = append(values, uniforms[idx:idx+1]...)
|
||||
} else {
|
||||
values[len(values)-1] |= uniforms[idx] << (8 * byteAlign)
|
||||
}
|
||||
case shaderir.Float, shaderir.Int:
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
values = fillZerosToFitAlignment(values, 2)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
values = append(values, 0)
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Mat2:
|
||||
values = fillZerosToFitAlignment(values, 2)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Mat3:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
values = append(values, uniforms[idx:idx+3]...)
|
||||
values = append(values, 0)
|
||||
values = append(values, uniforms[idx+3:idx+6]...)
|
||||
values = append(values, 0)
|
||||
values = append(values, uniforms[idx+6:idx+9]...)
|
||||
values = append(values, 0)
|
||||
case shaderir.Mat4:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
if i == graphics.ProjectionMatrixUniformVariableIndex {
|
||||
// In Metal, the NDC's Y direction (upward) and the framebuffer's Y direction (downward) don't
|
||||
// match. Then, the Y direction must be inverted.
|
||||
// Invert the sign bits as float32 values.
|
||||
u := uniforms[idx : idx+16]
|
||||
values = append(values,
|
||||
u[0], u[1]^uint32(1<<31), u[2], u[3],
|
||||
u[4], u[5]^uint32(1<<31), u[6], u[7],
|
||||
u[8], u[9]^uint32(1<<31), u[10], u[11],
|
||||
u[12], u[13]^uint32(1<<31), u[14], u[15],
|
||||
)
|
||||
} else {
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
}
|
||||
case shaderir.Array:
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Bool:
|
||||
for i := range n {
|
||||
if (i+byteAlign)%4 == 0 {
|
||||
values = append(values, uniforms[idx+i])
|
||||
} else {
|
||||
values[len(values)-1] |= uniforms[idx+i] << (8 * ((i + byteAlign) % 4))
|
||||
}
|
||||
}
|
||||
case shaderir.Float, shaderir.Int:
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
values = fillZerosToFitAlignment(values, 2)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
values = append(values, uniforms[idx+3*j:idx+3*(j+1)]...)
|
||||
values = append(values, 0)
|
||||
}
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Mat2:
|
||||
values = fillZerosToFitAlignment(values, 2)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
case shaderir.Mat3:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
values = append(values, uniforms[idx+9*j:idx+9*j+3]...)
|
||||
values = append(values, 0)
|
||||
values = append(values, uniforms[idx+9*j+3:idx+9*j+6]...)
|
||||
values = append(values, 0)
|
||||
values = append(values, uniforms[idx+9*j+6:idx+9*j+9]...)
|
||||
values = append(values, 0)
|
||||
}
|
||||
case shaderir.Mat4:
|
||||
values = fillZerosToFitAlignment(values, 4)
|
||||
values = append(values, uniforms[idx:idx+n]...)
|
||||
default:
|
||||
panic(fmt.Sprintf("metal: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("metal: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
|
||||
idx += n
|
||||
|
||||
if typ.Main == shaderir.Bool || (typ.Main == shaderir.Array && typ.Sub[0].Main == shaderir.Bool) {
|
||||
byteAlign += n
|
||||
byteAlign %= 4
|
||||
} else {
|
||||
byteAlign = 0
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
Generated
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mtl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
var libSystem uintptr
|
||||
|
||||
var (
|
||||
dispatchDataCreate func(buffer unsafe.Pointer, size uint, queue uintptr, destructor uintptr) uintptr
|
||||
dispatchRelease func(obj uintptr)
|
||||
)
|
||||
|
||||
func init() {
|
||||
lib, err := purego.Dlopen("/usr/lib/libSystem.B.dylib", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
libSystem = lib
|
||||
|
||||
purego.RegisterLibFunc(&dispatchDataCreate, libSystem, "dispatch_data_create")
|
||||
purego.RegisterLibFunc(&dispatchRelease, libSystem, "dispatch_release")
|
||||
}
|
||||
Generated
Vendored
+160
-144
@@ -36,7 +36,7 @@ import (
|
||||
|
||||
// GPUFamily represents the functionality for families of GPUs.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlgpufamily
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlgpufamily?language=objc.
|
||||
type GPUFamily int
|
||||
|
||||
const (
|
||||
@@ -54,7 +54,7 @@ const (
|
||||
|
||||
// FeatureSet defines a specific platform, hardware, and software configuration.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlfeatureset.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlfeatureset?language=objc.
|
||||
type FeatureSet uint16
|
||||
|
||||
const (
|
||||
@@ -92,7 +92,7 @@ const (
|
||||
// TextureType defines The dimension of each image, including whether multiple images are arranged into an array or
|
||||
// a cube.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexturetype
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexturetype?language=objc.
|
||||
type TextureType uint16
|
||||
|
||||
const (
|
||||
@@ -102,7 +102,7 @@ const (
|
||||
// PixelFormat defines data formats that describe the organization
|
||||
// and characteristics of individual pixels in a texture.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlpixelformat.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlpixelformat?language=objc.
|
||||
type PixelFormat uint16
|
||||
|
||||
// The data formats that describe the organization and characteristics
|
||||
@@ -117,7 +117,7 @@ const (
|
||||
|
||||
// PrimitiveType defines geometric primitive types for drawing commands.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlprimitivetype.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlprimitivetype?language=objc.
|
||||
type PrimitiveType uint8
|
||||
|
||||
// Geometric primitive types for drawing commands.
|
||||
@@ -132,7 +132,7 @@ const (
|
||||
// LoadAction defines actions performed at the start of a rendering pass
|
||||
// for a render command encoder.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlloadaction.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlloadaction?language=objc.
|
||||
type LoadAction uint8
|
||||
|
||||
// Actions performed at the start of a rendering pass for a render command encoder.
|
||||
@@ -145,7 +145,7 @@ const (
|
||||
// StoreAction defines actions performed at the end of a rendering pass
|
||||
// for a render command encoder.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoreaction.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoreaction?language=objc.
|
||||
type StoreAction uint8
|
||||
|
||||
// Actions performed at the end of a rendering pass for a render command encoder.
|
||||
@@ -160,7 +160,7 @@ const (
|
||||
|
||||
// StorageMode defines the memory location and access permissions of a resource.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoragemode.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoragemode?language=objc.
|
||||
type StorageMode uint8
|
||||
|
||||
const (
|
||||
@@ -189,7 +189,7 @@ const (
|
||||
// ResourceOptions defines optional arguments used to create
|
||||
// and influence behavior of buffer and texture objects.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlresourceoptions.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlresourceoptions?language=objc.
|
||||
type ResourceOptions uint16
|
||||
|
||||
const (
|
||||
@@ -237,7 +237,7 @@ const (
|
||||
|
||||
// CPUCacheMode is the CPU cache mode that defines the CPU mapping of a resource.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcpucachemode.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcpucachemode?language=objc.
|
||||
type CPUCacheMode uint8
|
||||
|
||||
const (
|
||||
@@ -252,7 +252,7 @@ const (
|
||||
|
||||
// IndexType is the index type for an index buffer that references vertices of geometric primitives.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoragemode
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstoragemode?language=objc
|
||||
type IndexType uint8
|
||||
|
||||
const (
|
||||
@@ -358,7 +358,7 @@ const (
|
||||
// Resource represents a memory allocation for storing specialized data
|
||||
// that is accessible to the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlresource.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlresource?language=objc.
|
||||
type Resource interface {
|
||||
// resource returns the underlying id<MTLResource> pointer.
|
||||
resource() unsafe.Pointer
|
||||
@@ -366,7 +366,7 @@ type Resource interface {
|
||||
|
||||
// RenderPipelineDescriptor configures new RenderPipelineState objects.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor?language=objc.
|
||||
type RenderPipelineDescriptor struct {
|
||||
// VertexFunction is a programmable function that processes individual vertices in a rendering pass.
|
||||
VertexFunction Function
|
||||
@@ -384,7 +384,7 @@ type RenderPipelineDescriptor struct {
|
||||
// RenderPipelineColorAttachmentDescriptor describes a color render target that specifies
|
||||
// the color configuration and color operations associated with a render pipeline.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinecolorattachmentdescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinecolorattachmentdescriptor?language=objc.
|
||||
type RenderPipelineColorAttachmentDescriptor struct {
|
||||
// PixelFormat is the pixel format of the color attachment's texture.
|
||||
PixelFormat PixelFormat
|
||||
@@ -404,7 +404,7 @@ type RenderPipelineColorAttachmentDescriptor struct {
|
||||
// RenderPassDescriptor describes a group of render targets that serve as
|
||||
// the output destination for pixels generated by a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor?language=objc.
|
||||
type RenderPassDescriptor struct {
|
||||
// ColorAttachments is array of state information for attachments that store color data.
|
||||
ColorAttachments [1]RenderPassColorAttachmentDescriptor
|
||||
@@ -416,7 +416,7 @@ type RenderPassDescriptor struct {
|
||||
// RenderPassColorAttachmentDescriptor describes a color render target that serves
|
||||
// as the output destination for color pixels generated by a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpasscolorattachmentdescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpasscolorattachmentdescriptor?language=objc.
|
||||
type RenderPassColorAttachmentDescriptor struct {
|
||||
RenderPassAttachmentDescriptor
|
||||
ClearColor ClearColor
|
||||
@@ -425,7 +425,7 @@ type RenderPassColorAttachmentDescriptor struct {
|
||||
// RenderPassStencilAttachment describes a stencil render target that serves as the output
|
||||
// destination for stencil pixels generated by a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassstencilattachmentdescriptor
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassstencilattachmentdescriptor?language=objc.
|
||||
type RenderPassStencilAttachment struct {
|
||||
RenderPassAttachmentDescriptor
|
||||
}
|
||||
@@ -433,7 +433,7 @@ type RenderPassStencilAttachment struct {
|
||||
// RenderPassAttachmentDescriptor describes a render target that serves
|
||||
// as the output destination for pixels generated by a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassattachmentdescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpassattachmentdescriptor?language=objc.
|
||||
type RenderPassAttachmentDescriptor struct {
|
||||
LoadAction LoadAction
|
||||
StoreAction StoreAction
|
||||
@@ -442,14 +442,14 @@ type RenderPassAttachmentDescriptor struct {
|
||||
|
||||
// ClearColor is an RGBA value used for a color pixel.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlclearcolor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlclearcolor?language=objc.
|
||||
type ClearColor struct {
|
||||
Red, Green, Blue, Alpha float64
|
||||
}
|
||||
|
||||
// TextureDescriptor configures new Texture objects.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexturedescriptor.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexturedescriptor?language=objc.
|
||||
type TextureDescriptor struct {
|
||||
TextureType TextureType
|
||||
PixelFormat PixelFormat
|
||||
@@ -462,7 +462,7 @@ type TextureDescriptor struct {
|
||||
// Device is abstract representation of the GPU that
|
||||
// serves as the primary interface for a Metal app.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice?language=objc.
|
||||
type Device struct {
|
||||
device objc.ID
|
||||
|
||||
@@ -484,7 +484,6 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
sel_class = objc.RegisterName("class")
|
||||
sel_length = objc.RegisterName("length")
|
||||
sel_isHeadless = objc.RegisterName("isHeadless")
|
||||
sel_isLowPower = objc.RegisterName("isLowPower")
|
||||
@@ -493,6 +492,7 @@ var (
|
||||
sel_supportsFeatureSet = objc.RegisterName("supportsFeatureSet:")
|
||||
sel_newCommandQueue = objc.RegisterName("newCommandQueue")
|
||||
sel_newLibraryWithSource_options_error = objc.RegisterName("newLibraryWithSource:options:error:")
|
||||
sel_newLibraryWithData_error = objc.RegisterName("newLibraryWithData:error:")
|
||||
sel_release = objc.RegisterName("release")
|
||||
sel_retain = objc.RegisterName("retain")
|
||||
sel_new = objc.RegisterName("new")
|
||||
@@ -567,7 +567,7 @@ var (
|
||||
|
||||
// CreateSystemDefaultDevice returns the preferred system default Metal device.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice.
|
||||
// Reference: https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice?language=objc.
|
||||
func CreateSystemDefaultDevice() (Device, error) {
|
||||
metal, err := purego.Dlopen("/System/Library/Frameworks/Metal.framework/Metal", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
@@ -607,37 +607,36 @@ func (d Device) Device() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Point
|
||||
|
||||
// RespondsToSelector returns a Boolean value that indicates whether the receiver implements or inherits a method that can respond to a specified message.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418583-respondstoselector
|
||||
// Reference: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418583-respondstoselector?language=objc.
|
||||
func (d Device) RespondsToSelector(sel objc.SEL) bool {
|
||||
return d.device.Send(sel_respondsToSelector, sel) != 0
|
||||
}
|
||||
|
||||
// SupportsFamily returns a Boolean value that indicates whether the GPU device supports the feature set of a specific GPU family.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/3143473-supportsfamily
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/3143473-supportsfamily?language=objc.
|
||||
func (d Device) SupportsFamily(gpuFamily GPUFamily) bool {
|
||||
return d.device.Send(sel_supportsFamily, uintptr(gpuFamily)) != 0
|
||||
}
|
||||
|
||||
// SupportsFeatureSet reports whether device d supports feature set fs.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433418-supportsfeatureset.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433418-supportsfeatureset?language=objc.
|
||||
func (d Device) SupportsFeatureSet(fs FeatureSet) bool {
|
||||
return d.device.Send(sel_supportsFeatureSet, uintptr(fs)) != 0
|
||||
}
|
||||
|
||||
// MakeCommandQueue creates a serial command submission queue.
|
||||
// NewCommandQueue creates a queue you use to submit rendering and computation commands to a GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433388-makecommandqueue.
|
||||
func (d Device) MakeCommandQueue() CommandQueue {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433388-newcommandqueue?language=objc.
|
||||
func (d Device) NewCommandQueue() CommandQueue {
|
||||
return CommandQueue{d.device.Send(sel_newCommandQueue)}
|
||||
}
|
||||
|
||||
// MakeLibrary creates a new library that contains
|
||||
// the functions stored in the specified source string.
|
||||
// NewLibraryWithSource synchronously creates a Metal library instance by compiling the functions in a source string.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433431-makelibrary.
|
||||
func (d Device) MakeLibrary(source string, opt CompileOptions) (Library, error) {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433431-newlibrarywithsource?language=objc.
|
||||
func (d Device) NewLibraryWithSource(source string, opt CompileOptions) (Library, error) {
|
||||
var err cocoa.NSError
|
||||
l := d.device.Send(
|
||||
sel_newLibraryWithSource_options_error,
|
||||
@@ -652,10 +651,31 @@ func (d Device) MakeLibrary(source string, opt CompileOptions) (Library, error)
|
||||
return Library{l}, nil
|
||||
}
|
||||
|
||||
// MakeRenderPipelineState creates a render pipeline state object.
|
||||
// NewLibraryWithData Creates a Metal library instance that contains the functions in a precompiled Metal library.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433369-makerenderpipelinestate.
|
||||
func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPipelineState, error) {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433391-newlibrarywithdata?language=objc.
|
||||
func (d Device) NewLibraryWithData(buffer []byte) (Library, error) {
|
||||
defer runtime.KeepAlive(buffer)
|
||||
|
||||
data := dispatchDataCreate(unsafe.Pointer(&buffer[0]), uint(len(buffer)), 0, 0)
|
||||
defer dispatchRelease(data)
|
||||
|
||||
var err cocoa.NSError
|
||||
l := d.device.Send(
|
||||
sel_newLibraryWithData_error,
|
||||
data,
|
||||
unsafe.Pointer(&err),
|
||||
)
|
||||
if l == 0 {
|
||||
return Library{}, errors.New(cocoa.NSString{ID: err.Send(sel_localizedDescription)}.String())
|
||||
}
|
||||
return Library{l}, nil
|
||||
}
|
||||
|
||||
// NewRenderPipelineStateWithDescriptor synchronously creates a render pipeline state.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433369-newrenderpipelinestatewithdescri?language=objc.
|
||||
func (d Device) NewRenderPipelineStateWithDescriptor(rpd RenderPipelineDescriptor) (RenderPipelineState, error) {
|
||||
renderPipelineDescriptor := objc.ID(class_MTLRenderPipelineDescriptor).Send(sel_new)
|
||||
renderPipelineDescriptor.Send(sel_setVertexFunction, rpd.VertexFunction.function)
|
||||
renderPipelineDescriptor.Send(sel_setFragmentFunction, rpd.FragmentFunction.function)
|
||||
@@ -683,26 +703,24 @@ func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPip
|
||||
return RenderPipelineState{renderPipelineState}, nil
|
||||
}
|
||||
|
||||
// MakeBufferWithBytes allocates a new buffer of a given length
|
||||
// and initializes its contents by copying existing data into it.
|
||||
// NewBufferWithBytes allocates a new buffer of a given length and initializes its contents by copying existing data into it.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433429-makebuffer.
|
||||
func (d Device) MakeBufferWithBytes(bytes unsafe.Pointer, length uintptr, opt ResourceOptions) Buffer {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433429-newbufferwithbytes?language=objc.
|
||||
func (d Device) NewBufferWithBytes(bytes unsafe.Pointer, length uintptr, opt ResourceOptions) Buffer {
|
||||
return Buffer{d.device.Send(sel_newBufferWithBytes_length_options, bytes, length, uintptr(opt))}
|
||||
}
|
||||
|
||||
// MakeBufferWithLength allocates a new zero-filled buffer of a given length.
|
||||
// NewBufferWithLength allocates a new zero-filled buffer of a given length.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433375-newbufferwithlength
|
||||
func (d Device) MakeBufferWithLength(length uintptr, opt ResourceOptions) Buffer {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433375-newbufferwithlength?language=objc.
|
||||
func (d Device) NewBufferWithLength(length uintptr, opt ResourceOptions) Buffer {
|
||||
return Buffer{d.device.Send(sel_newBufferWithLength_options, length, uintptr(opt))}
|
||||
}
|
||||
|
||||
// MakeTexture creates a texture object with privately owned storage
|
||||
// that contains texture state.
|
||||
// NewTextureWithDescriptor creates a new texture instance.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433425-maketexture.
|
||||
func (d Device) MakeTexture(td TextureDescriptor) Texture {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433425-newtexturewithdescriptor?language=objc.
|
||||
func (d Device) NewTextureWithDescriptor(td TextureDescriptor) Texture {
|
||||
textureDescriptor := objc.ID(class_MTLTextureDescriptor).Send(sel_new)
|
||||
textureDescriptor.Send(sel_setTextureType, uintptr(td.TextureType))
|
||||
textureDescriptor.Send(sel_setPixelFormat, uintptr(td.PixelFormat))
|
||||
@@ -717,10 +735,10 @@ func (d Device) MakeTexture(td TextureDescriptor) Texture {
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDepthStencilState creates a new object that contains depth and stencil test state.
|
||||
// NewDepthStencilStateWithDescriptor creates a depth-stencil state instance.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433412-makedepthstencilstate
|
||||
func (d Device) MakeDepthStencilState(dsd DepthStencilDescriptor) DepthStencilState {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldevice/1433412-newdepthstencilstatewithdescript?language=objc.
|
||||
func (d Device) NewDepthStencilStateWithDescriptor(dsd DepthStencilDescriptor) DepthStencilState {
|
||||
depthStencilDescriptor := objc.ID(class_MTLDepthStencilDescriptor).Send(sel_new)
|
||||
backFaceStencil := depthStencilDescriptor.Send(sel_backFaceStencil)
|
||||
backFaceStencil.Send(sel_setStencilFailureOperation, uintptr(dsd.BackFaceStencil.StencilFailureOperation))
|
||||
@@ -742,14 +760,14 @@ func (d Device) MakeDepthStencilState(dsd DepthStencilDescriptor) DepthStencilSt
|
||||
// CompileOptions specifies optional compilation settings for
|
||||
// the graphics or compute functions within a library.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcompileoptions.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcompileoptions?language=objc.
|
||||
type CompileOptions struct {
|
||||
// TODO.
|
||||
}
|
||||
|
||||
// Drawable is a displayable resource that can be rendered or written to.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldrawable.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldrawable?language=objc.
|
||||
type Drawable interface {
|
||||
// Drawable returns the underlying id<MTLDrawable> pointer.
|
||||
Drawable() unsafe.Pointer
|
||||
@@ -758,7 +776,7 @@ type Drawable interface {
|
||||
// CommandQueue is a queue that organizes the order
|
||||
// in which command buffers are executed by the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue?language=objc.
|
||||
type CommandQueue struct {
|
||||
commandQueue objc.ID
|
||||
}
|
||||
@@ -767,17 +785,17 @@ func (cq CommandQueue) Release() {
|
||||
cq.commandQueue.Send(sel_release)
|
||||
}
|
||||
|
||||
// MakeCommandBuffer creates a command buffer.
|
||||
// CommandBuffer returns a command buffer from the command queue that maintains strong references to resources.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue/1508686-makecommandbuffer.
|
||||
func (cq CommandQueue) MakeCommandBuffer() CommandBuffer {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue/1508686-commandbuffer?language=objc.
|
||||
func (cq CommandQueue) CommandBuffer() CommandBuffer {
|
||||
return CommandBuffer{cq.commandQueue.Send(sel_commandBuffer)}
|
||||
}
|
||||
|
||||
// CommandBuffer is a container that stores encoded commands
|
||||
// that are committed to and executed by the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer?language=objc.
|
||||
type CommandBuffer struct {
|
||||
commandBuffer objc.ID
|
||||
}
|
||||
@@ -792,55 +810,49 @@ func (cb CommandBuffer) Release() {
|
||||
|
||||
// Status returns the current stage in the lifetime of the command buffer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443048-status
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443048-status?language=objc.
|
||||
func (cb CommandBuffer) Status() CommandBufferStatus {
|
||||
return CommandBufferStatus(cb.commandBuffer.Send(sel_status))
|
||||
}
|
||||
|
||||
// PresentDrawable registers a drawable presentation to occur as soon as possible.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443029-presentdrawable.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443029-presentdrawable?language=objc.
|
||||
func (cb CommandBuffer) PresentDrawable(d Drawable) {
|
||||
cb.commandBuffer.Send(sel_presentDrawable, d.Drawable())
|
||||
}
|
||||
|
||||
// Commit commits this command buffer for execution as soon as possible.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443003-commit.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443003-commit?language=objc.
|
||||
func (cb CommandBuffer) Commit() {
|
||||
cb.commandBuffer.Send(sel_commit)
|
||||
}
|
||||
|
||||
// WaitUntilCompleted waits for the execution of this command buffer to complete.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443039-waituntilcompleted.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443039-waituntilcompleted?language=objc.
|
||||
func (cb CommandBuffer) WaitUntilCompleted() {
|
||||
cb.commandBuffer.Send(sel_waitUntilCompleted)
|
||||
}
|
||||
|
||||
// WaitUntilScheduled blocks execution of the current thread until the command buffer is scheduled.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443036-waituntilscheduled.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443036-waituntilscheduled?language=objc.
|
||||
func (cb CommandBuffer) WaitUntilScheduled() {
|
||||
cb.commandBuffer.Send(sel_waitUntilScheduled)
|
||||
}
|
||||
|
||||
// MakeRenderCommandEncoder creates an encoder object that can
|
||||
// encode graphics rendering commands into this command buffer.
|
||||
// RenderCommandEncoderWithDescriptor creates a render command encoder from a descriptor.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1442999-makerendercommandencoder.
|
||||
func (cb CommandBuffer) MakeRenderCommandEncoder(rpd RenderPassDescriptor) RenderCommandEncoder {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1442999-rendercommandencoderwithdescript?language=objc.
|
||||
func (cb CommandBuffer) RenderCommandEncoderWithDescriptor(rpd RenderPassDescriptor) RenderCommandEncoder {
|
||||
var renderPassDescriptor = objc.ID(class_MTLRenderPassDescriptor).Send(sel_new)
|
||||
var colorAttachments0 = renderPassDescriptor.Send(sel_colorAttachments).Send(sel_objectAtIndexedSubscript, 0)
|
||||
colorAttachments0.Send(sel_setLoadAction, int(rpd.ColorAttachments[0].LoadAction))
|
||||
colorAttachments0.Send(sel_setStoreAction, int(rpd.ColorAttachments[0].StoreAction))
|
||||
colorAttachments0.Send(sel_setTexture, rpd.ColorAttachments[0].Texture.texture)
|
||||
sig := cocoa.NSMethodSignature_instanceMethodSignatureForSelector(colorAttachments0.Send(sel_class), sel_setClearColor)
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetTarget(colorAttachments0)
|
||||
inv.SetSelector(sel_setClearColor)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&rpd.ColorAttachments[0].ClearColor), 2)
|
||||
inv.Invoke()
|
||||
colorAttachments0.Send(sel_setClearColor, rpd.ColorAttachments[0].ClearColor)
|
||||
var stencilAttachment = renderPassDescriptor.Send(sel_stencilAttachment)
|
||||
stencilAttachment.Send(sel_setLoadAction, int(rpd.StencilAttachment.LoadAction))
|
||||
stencilAttachment.Send(sel_setStoreAction, int(rpd.StencilAttachment.StoreAction))
|
||||
@@ -850,11 +862,11 @@ func (cb CommandBuffer) MakeRenderCommandEncoder(rpd RenderPassDescriptor) Rende
|
||||
return RenderCommandEncoder{CommandEncoder{rce}}
|
||||
}
|
||||
|
||||
// MakeBlitCommandEncoder creates an encoder object that can encode
|
||||
// BlitCommandEncoder creates an encoder object that can encode
|
||||
// memory operation (blit) commands into this command buffer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443001-makeblitcommandencoder.
|
||||
func (cb CommandBuffer) MakeBlitCommandEncoder() BlitCommandEncoder {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443001-makeblitcommandencoder?language=objc.
|
||||
func (cb CommandBuffer) BlitCommandEncoder() BlitCommandEncoder {
|
||||
ce := cb.commandBuffer.Send(sel_blitCommandEncoder)
|
||||
return BlitCommandEncoder{CommandEncoder{ce}}
|
||||
}
|
||||
@@ -862,14 +874,14 @@ func (cb CommandBuffer) MakeBlitCommandEncoder() BlitCommandEncoder {
|
||||
// CommandEncoder is an encoder that writes sequential GPU commands
|
||||
// into a command buffer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443001-blitcommandencoder?language=objc.
|
||||
type CommandEncoder struct {
|
||||
commandEncoder objc.ID
|
||||
}
|
||||
|
||||
// EndEncoding declares that all command generation from this encoder is completed.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder/1458038-endencoding.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder/1458038-endencoding?language=objc.
|
||||
func (ce CommandEncoder) EndEncoding() {
|
||||
ce.commandEncoder.Send(sel_endEncoding)
|
||||
}
|
||||
@@ -877,7 +889,7 @@ func (ce CommandEncoder) EndEncoding() {
|
||||
// RenderCommandEncoder is an encoder that specifies graphics-rendering commands
|
||||
// and executes graphics functions.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder?language=objc.
|
||||
type RenderCommandEncoder struct {
|
||||
CommandEncoder
|
||||
}
|
||||
@@ -888,41 +900,33 @@ func (rce RenderCommandEncoder) Release() {
|
||||
|
||||
// SetRenderPipelineState sets the current render pipeline state object.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515811-setrenderpipelinestate.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515811-setrenderpipelinestate?language=objc.
|
||||
func (rce RenderCommandEncoder) SetRenderPipelineState(rps RenderPipelineState) {
|
||||
rce.commandEncoder.Send(sel_setRenderPipelineState, rps.renderPipelineState)
|
||||
}
|
||||
|
||||
func (rce RenderCommandEncoder) SetViewport(viewport Viewport) {
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLViewport=dddddd}"))
|
||||
inv.SetTarget(rce.commandEncoder)
|
||||
inv.SetSelector(sel_setViewport)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&viewport), 2)
|
||||
inv.Invoke()
|
||||
rce.commandEncoder.Send(sel_setViewport, viewport)
|
||||
}
|
||||
|
||||
// SetScissorRect sets the scissor rectangle for a fragment scissor test.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515583-setscissorrect
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515583-setscissorrect?language=objc.
|
||||
func (rce RenderCommandEncoder) SetScissorRect(scissorRect ScissorRect) {
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLScissorRect=qqqq}"))
|
||||
inv.SetTarget(rce.commandEncoder)
|
||||
inv.SetSelector(sel_setScissorRect)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&scissorRect), 2)
|
||||
inv.Invoke()
|
||||
rce.commandEncoder.Send(sel_setScissorRect, scissorRect)
|
||||
}
|
||||
|
||||
// SetVertexBuffer sets a buffer for the vertex shader function at an index
|
||||
// in the buffer argument table with an offset that specifies the start of the data.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515829-setvertexbuffer.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515829-setvertexbuffer?language=objc.
|
||||
func (rce RenderCommandEncoder) SetVertexBuffer(buf Buffer, offset, index int) {
|
||||
rce.commandEncoder.Send(sel_setVertexBuffer_offset_atIndex, buf.buffer, offset, index)
|
||||
}
|
||||
|
||||
// SetVertexBytes sets a block of data for the vertex function.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515846-setvertexbytes.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515846-setvertexbytes?language=objc.
|
||||
func (rce RenderCommandEncoder) SetVertexBytes(bytes unsafe.Pointer, length uintptr, index int) {
|
||||
rce.commandEncoder.Send(sel_setVertexBytes_length_atIndex, bytes, length, index)
|
||||
}
|
||||
@@ -933,7 +937,7 @@ func (rce RenderCommandEncoder) SetFragmentBytes(bytes unsafe.Pointer, length ui
|
||||
|
||||
// SetFragmentTexture sets a texture for the fragment function at an index in the texture argument table.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515390-setfragmenttexture
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515390-setfragmenttexture?language=objc.
|
||||
func (rce RenderCommandEncoder) SetFragmentTexture(texture Texture, index int) {
|
||||
rce.commandEncoder.Send(sel_setFragmentTexture_atIndex, texture.texture, index)
|
||||
}
|
||||
@@ -944,7 +948,7 @@ func (rce RenderCommandEncoder) SetBlendColor(red, green, blue, alpha float32) {
|
||||
|
||||
// SetDepthStencilState sets the depth and stencil test state.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516119-setdepthstencilstate
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516119-setdepthstencilstate?language=objc.
|
||||
func (rce RenderCommandEncoder) SetDepthStencilState(depthStencilState DepthStencilState) {
|
||||
rce.commandEncoder.Send(sel_setDepthStencilState, depthStencilState.depthStencilState)
|
||||
}
|
||||
@@ -952,7 +956,7 @@ func (rce RenderCommandEncoder) SetDepthStencilState(depthStencilState DepthSten
|
||||
// DrawPrimitives renders one instance of primitives using vertex data
|
||||
// in contiguous array elements.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516326-drawprimitives.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516326-drawprimitives?language=objc.
|
||||
func (rce RenderCommandEncoder) DrawPrimitives(typ PrimitiveType, vertexStart, vertexCount int) {
|
||||
rce.commandEncoder.Send(sel_drawPrimitives_vertexStart_vertexCount, uintptr(typ), vertexStart, vertexCount)
|
||||
}
|
||||
@@ -969,7 +973,7 @@ func (rce RenderCommandEncoder) DrawIndexedPrimitives(typ PrimitiveType, indexCo
|
||||
// BlitCommandEncoder is an encoder that specifies resource copy
|
||||
// and resource synchronization commands.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder?language=objc.
|
||||
type BlitCommandEncoder struct {
|
||||
CommandEncoder
|
||||
}
|
||||
@@ -977,7 +981,7 @@ type BlitCommandEncoder struct {
|
||||
// Synchronize flushes any copy of the specified resource from its corresponding
|
||||
// Device caches and, if needed, invalidates any CPU caches.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400775-synchronize.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400775-synchronize?language=objc.
|
||||
func (bce BlitCommandEncoder) Synchronize(resource Resource) {
|
||||
if runtime.GOOS == "ios" {
|
||||
return
|
||||
@@ -985,6 +989,9 @@ func (bce BlitCommandEncoder) Synchronize(resource Resource) {
|
||||
bce.commandEncoder.Send(sel_synchronizeResource, resource.resource())
|
||||
}
|
||||
|
||||
// SynchronizeTexture encodes a command that synchronizes a part of the CPU’s copy of a texture so that it matches the GPU’s copy.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400757-synchronizetexture?language=objc.
|
||||
func (bce BlitCommandEncoder) SynchronizeTexture(texture Texture, slice int, level int) {
|
||||
if runtime.GOOS == "ios" {
|
||||
return
|
||||
@@ -992,7 +999,11 @@ func (bce BlitCommandEncoder) SynchronizeTexture(texture Texture, slice int, lev
|
||||
bce.commandEncoder.Send(sel_synchronizeTexture_slice_level, texture.texture, slice, level)
|
||||
}
|
||||
|
||||
// CopyFromTexture encodes a command that copies image data from a texture’s slice into another slice.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400754-copyfromtexture?language=objc.
|
||||
func (bce BlitCommandEncoder) CopyFromTexture(sourceTexture Texture, sourceSlice int, sourceLevel int, sourceOrigin Origin, sourceSize Size, destinationTexture Texture, destinationSlice int, destinationLevel int, destinationOrigin Origin) {
|
||||
// copyFromTexture requires so many arguments that Send doesn't work (#3135).
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:@QQ{MTLOrigin=qqq}{MTLSize=qqq}@QQ{MTLOrigin=qqq}"))
|
||||
inv.SetTarget(bce.commandEncoder)
|
||||
inv.SetSelector(sel_copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin)
|
||||
@@ -1010,15 +1021,15 @@ func (bce BlitCommandEncoder) CopyFromTexture(sourceTexture Texture, sourceSlice
|
||||
|
||||
// Library is a collection of compiled graphics or compute functions.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtllibrary.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtllibrary?language=objc.
|
||||
type Library struct {
|
||||
library objc.ID
|
||||
}
|
||||
|
||||
// MakeFunction returns a pre-compiled, non-specialized function.
|
||||
// NewFunctionWithName returns a pre-compiled, non-specialized function.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtllibrary/1515524-makefunction.
|
||||
func (l Library) MakeFunction(name string) (Function, error) {
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtllibrary/1515524-newfunctionwithname?language=objc.
|
||||
func (l Library) NewFunctionWithName(name string) (Function, error) {
|
||||
f := l.library.Send(sel_newFunctionWithName,
|
||||
cocoa.NSString_alloc().InitWithUTF8String(name).ID,
|
||||
)
|
||||
@@ -1028,10 +1039,14 @@ func (l Library) MakeFunction(name string) (Function, error) {
|
||||
return Function{f}, nil
|
||||
}
|
||||
|
||||
func (l Library) Release() {
|
||||
l.library.Send(sel_release)
|
||||
}
|
||||
|
||||
// Texture is a memory allocation for storing formatted
|
||||
// image data that is accessible to the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture?language=objc.
|
||||
type Texture struct {
|
||||
texture objc.ID
|
||||
}
|
||||
@@ -1042,7 +1057,9 @@ func NewTexture(texture objc.ID) Texture {
|
||||
}
|
||||
|
||||
// resource implements the Resource interface.
|
||||
func (t Texture) resource() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&t.texture)) }
|
||||
func (t Texture) resource() unsafe.Pointer {
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&t.texture))
|
||||
}
|
||||
|
||||
func (t Texture) Release() {
|
||||
t.texture.Send(sel_release)
|
||||
@@ -1051,42 +1068,28 @@ func (t Texture) Release() {
|
||||
// GetBytes copies a block of pixels from the storage allocation of texture
|
||||
// slice zero into system memory at a specified address.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515751-getbytes.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515751-getbytes?language=objc.
|
||||
func (t Texture) GetBytes(pixelBytes *byte, bytesPerRow uintptr, region Region, level int) {
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:^vQ{MTLRegion={MTLOrigin=qqq}{MTLSize=qqq}}Q"))
|
||||
inv.SetTarget(t.texture)
|
||||
inv.SetSelector(sel_getBytes_bytesPerRow_fromRegion_mipmapLevel)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&pixelBytes), 2)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&bytesPerRow), 3)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(®ion), 4)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&level), 5)
|
||||
inv.Invoke()
|
||||
t.texture.Send(sel_getBytes_bytesPerRow_fromRegion_mipmapLevel, pixelBytes, bytesPerRow, region, level)
|
||||
}
|
||||
|
||||
// ReplaceRegion copies a block of pixels from the caller's pointer into the storage allocation for slice 0 of a texture.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515464-replaceregion
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515464-replaceregion?language=objc.
|
||||
func (t Texture) ReplaceRegion(region Region, level int, pixelBytes unsafe.Pointer, bytesPerRow int) {
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(cocoa.NSMethodSignature_signatureWithObjCTypes("v@:{MTLRegion={MTLOrigin=qqq}{MTLSize=qqq}}Q^vQ"))
|
||||
inv.SetTarget(t.texture)
|
||||
inv.SetSelector(sel_replaceRegion_mipmapLevel_withBytes_bytesPerRow)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(®ion), 2)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&level), 3)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&pixelBytes), 4)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&bytesPerRow), 5)
|
||||
inv.Invoke()
|
||||
t.texture.Send(sel_replaceRegion_mipmapLevel_withBytes_bytesPerRow, region, level, pixelBytes, bytesPerRow)
|
||||
}
|
||||
|
||||
// Width is the width of the texture image for the base level mipmap, in pixels.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515339-width
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515339-width?language=objc.
|
||||
func (t Texture) Width() int {
|
||||
return int(t.texture.Send(sel_width))
|
||||
}
|
||||
|
||||
// Height is the height of the texture image for the base level mipmap, in pixels.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515938-height
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtltexture/1515938-height?language=objc.
|
||||
func (t Texture) Height() int {
|
||||
return int(t.texture.Send(sel_height))
|
||||
}
|
||||
@@ -1094,13 +1097,19 @@ func (t Texture) Height() int {
|
||||
// Buffer is a memory allocation for storing unformatted data
|
||||
// that is accessible to the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlbuffer.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlbuffer?language=objc.
|
||||
type Buffer struct {
|
||||
buffer objc.ID
|
||||
}
|
||||
|
||||
func (b Buffer) resource() unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&b.buffer)) }
|
||||
// resource implements the Resource interface.
|
||||
func (b Buffer) resource() unsafe.Pointer {
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&b.buffer))
|
||||
}
|
||||
|
||||
// Length returns the logical size of the buffer, in bytes.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlbuffer/1515373-length?language=objc.
|
||||
func (b Buffer) Length() uintptr {
|
||||
return uintptr(b.buffer.Send(sel_length))
|
||||
}
|
||||
@@ -1121,13 +1130,9 @@ func (b Buffer) Release() {
|
||||
b.buffer.Send(sel_release)
|
||||
}
|
||||
|
||||
func (b Buffer) Native() unsafe.Pointer {
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&b.buffer))
|
||||
}
|
||||
|
||||
// Function represents a programmable graphics or compute function executed by the GPU.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlfunction.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlfunction?language=objc.
|
||||
type Function struct {
|
||||
function objc.ID
|
||||
}
|
||||
@@ -1139,7 +1144,7 @@ func (f Function) Release() {
|
||||
// RenderPipelineState contains the graphics functions
|
||||
// and configuration state used in a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate?language=objc.
|
||||
type RenderPipelineState struct {
|
||||
renderPipelineState objc.ID
|
||||
}
|
||||
@@ -1151,7 +1156,7 @@ func (r RenderPipelineState) Release() {
|
||||
// Region is a rectangular block of pixels in an image or texture,
|
||||
// defined by its upper-left corner and its size.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlregion.
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlregion?language=objc.
|
||||
type Region struct {
|
||||
Origin Origin // The location of the upper-left corner of the block.
|
||||
Size Size // The size of the block.
|
||||
@@ -1160,25 +1165,36 @@ type Region struct {
|
||||
// Origin represents the location of a pixel in an image or texture relative
|
||||
// to the upper-left corner, whose coordinates are (0, 0).
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlorigin.
|
||||
type Origin struct{ X, Y, Z int }
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlorigin?language=objc.
|
||||
type Origin struct {
|
||||
X int
|
||||
Y int
|
||||
Z int
|
||||
}
|
||||
|
||||
// Size represents the set of dimensions that declare the size of an object,
|
||||
// such as an image, texture, threadgroup, or grid.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlsize.
|
||||
type Size struct{ Width, Height, Depth int }
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlsize?language=objc.
|
||||
type Size struct {
|
||||
Width int
|
||||
Height int
|
||||
Depth int
|
||||
}
|
||||
|
||||
// RegionMake2D returns a 2D, rectangular region for image or texture data.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/1515675-mtlregionmake2d.
|
||||
// Reference: https://developer.apple.com/documentation/metal/1515675-mtlregionmake2d?language=objc.
|
||||
func RegionMake2D(x, y, width, height int) Region {
|
||||
return Region{
|
||||
Origin: Origin{x, y, 0},
|
||||
Size: Size{width, height, 1},
|
||||
Origin: Origin{X: x, Y: y, Z: 0},
|
||||
Size: Size{Width: width, Height: height, Depth: 1},
|
||||
}
|
||||
}
|
||||
|
||||
// Viewport is a 3D rectangular region for the viewport clipping.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlviewport?language=objc.
|
||||
type Viewport struct {
|
||||
OriginX float64
|
||||
OriginY float64
|
||||
@@ -1188,9 +1204,9 @@ type Viewport struct {
|
||||
ZFar float64
|
||||
}
|
||||
|
||||
// ScissorRect represents a rectangle for the scissor fragment test.
|
||||
// ScissorRect is a rectangle for the scissor fragment test.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlscissorrect
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlscissorrect?language=objc.
|
||||
type ScissorRect struct {
|
||||
X int
|
||||
Y int
|
||||
@@ -1200,7 +1216,7 @@ type ScissorRect struct {
|
||||
|
||||
// DepthStencilState is a depth and stencil state object that specifies the depth and stencil configuration and operations used in a render pass.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldepthstencilstate
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldepthstencilstate?language=objc.
|
||||
type DepthStencilState struct {
|
||||
depthStencilState objc.ID
|
||||
}
|
||||
@@ -1211,7 +1227,7 @@ func (d DepthStencilState) Release() {
|
||||
|
||||
// DepthStencilDescriptor is an object that configures new MTLDepthStencilState objects.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldepthstencildescriptor
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldepthstencildescriptor?language=objc.
|
||||
type DepthStencilDescriptor struct {
|
||||
// BackFaceStencil is the stencil descriptor for back-facing primitives.
|
||||
BackFaceStencil StencilDescriptor
|
||||
@@ -1222,7 +1238,7 @@ type DepthStencilDescriptor struct {
|
||||
|
||||
// StencilDescriptor is an object that defines the front-facing or back-facing stencil operations of a depth and stencil state object.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstencildescriptor
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtlstencildescriptor?language=objc.
|
||||
type StencilDescriptor struct {
|
||||
// StencilFailureOperation is the operation that is performed to update the values in the stencil attachment when the stencil test fails.
|
||||
StencilFailureOperation StencilOperation
|
||||
|
||||
Generated
Vendored
+65
-9
@@ -16,6 +16,7 @@ package metal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
@@ -23,6 +24,37 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/msl"
|
||||
)
|
||||
|
||||
type precompiledLibraries struct {
|
||||
binaries map[shaderir.SourceHash][]byte
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (c *precompiledLibraries) put(hash shaderir.SourceHash, bin []byte) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if c.binaries == nil {
|
||||
c.binaries = map[shaderir.SourceHash][]byte{}
|
||||
}
|
||||
if _, ok := c.binaries[hash]; ok {
|
||||
panic(fmt.Sprintf("metal: the precompiled library for the hash %s is already registered", hash.String()))
|
||||
}
|
||||
c.binaries[hash] = bin
|
||||
}
|
||||
|
||||
func (c *precompiledLibraries) get(hash shaderir.SourceHash) []byte {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
return c.binaries[hash]
|
||||
}
|
||||
|
||||
var thePrecompiledLibraries precompiledLibraries
|
||||
|
||||
func RegisterPrecompiledLibrary(source []byte, bin []byte) {
|
||||
thePrecompiledLibraries.put(shaderir.CalcSourceHash(source), bin)
|
||||
}
|
||||
|
||||
type shaderRpsKey struct {
|
||||
blend graphicsdriver.Blend
|
||||
stencilMode stencilMode
|
||||
@@ -33,9 +65,12 @@ type Shader struct {
|
||||
id graphicsdriver.ShaderID
|
||||
|
||||
ir *shaderir.Program
|
||||
lib mtl.Library
|
||||
fs mtl.Function
|
||||
vs mtl.Function
|
||||
rpss map[shaderRpsKey]mtl.RenderPipelineState
|
||||
|
||||
libraryPrecompiled bool
|
||||
}
|
||||
|
||||
func newShader(device mtl.Device, id graphicsdriver.ShaderID, program *shaderir.Program) (*Shader, error) {
|
||||
@@ -60,21 +95,42 @@ func (s *Shader) Dispose() {
|
||||
}
|
||||
s.vs.Release()
|
||||
s.fs.Release()
|
||||
// Do not release s.lib if this is precompiled. This is a shared precompiled library.
|
||||
if !s.libraryPrecompiled {
|
||||
s.lib.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Shader) init(device mtl.Device) error {
|
||||
src := msl.Compile(s.ir)
|
||||
lib, err := device.MakeLibrary(src, mtl.CompileOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: device.MakeLibrary failed: %w, source: %s", err, src)
|
||||
var src string
|
||||
if libBin := thePrecompiledLibraries.get(s.ir.SourceHash); len(libBin) > 0 {
|
||||
lib, err := device.NewLibraryWithData(libBin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.lib = lib
|
||||
} else {
|
||||
src = msl.Compile(s.ir)
|
||||
lib, err := device.NewLibraryWithSource(src, mtl.CompileOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: device.MakeLibrary failed: %w, source: %s", err, src)
|
||||
}
|
||||
s.lib = lib
|
||||
}
|
||||
vs, err := lib.MakeFunction(msl.VertexName)
|
||||
|
||||
vs, err := s.lib.NewFunctionWithName(msl.VertexName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for vertex failed: %w, source: %s", err, src)
|
||||
if src != "" {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for vertex failed: %w, source: %s", err, src)
|
||||
}
|
||||
return fmt.Errorf("metal: lib.MakeFunction for vertex failed: %w", err)
|
||||
}
|
||||
fs, err := lib.MakeFunction(msl.FragmentName)
|
||||
fs, err := s.lib.NewFunctionWithName(msl.FragmentName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for fragment failed: %w, source: %s", err, src)
|
||||
if src != "" {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for fragment failed: %w, source: %s", err, src)
|
||||
}
|
||||
return fmt.Errorf("metal: lib.MakeFunction for fragment failed: %w", err)
|
||||
}
|
||||
s.fs = fs
|
||||
s.vs = vs
|
||||
@@ -120,7 +176,7 @@ func (s *Shader) RenderPipelineState(view *view, blend graphicsdriver.Blend, ste
|
||||
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
|
||||
}
|
||||
|
||||
rps, err := view.getMTLDevice().MakeRenderPipelineState(rpld)
|
||||
rps, err := view.getMTLDevice().NewRenderPipelineStateWithDescriptor(rpld)
|
||||
if err != nil {
|
||||
return mtl.RenderPipelineState{}, err
|
||||
}
|
||||
|
||||
Generated
Vendored
+56
-10
@@ -15,12 +15,22 @@
|
||||
package metal
|
||||
|
||||
import (
|
||||
"runtime/cgo"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
// maximumDrawableCount is the maximum number of drawable objects.
|
||||
//
|
||||
// Always use 3 for macOS (#2880, #2883, #3278).
|
||||
// At least, this should work with MacBook Pro 2020 (Intel) and MacBook Pro 2023 (M3).
|
||||
const maximumDrawableCount = 3
|
||||
|
||||
type view struct {
|
||||
window uintptr
|
||||
uiview uintptr
|
||||
@@ -32,6 +42,19 @@ type view struct {
|
||||
ml ca.MetalLayer
|
||||
|
||||
once sync.Once
|
||||
|
||||
caDisplayLink uintptr
|
||||
metalDisplayLink uintptr
|
||||
|
||||
// The following members are used only with CAMetalDisplayLink.
|
||||
drawableCh chan ca.MetalDrawable
|
||||
drawableDoneCh chan struct{}
|
||||
drawableTimer *time.Timer
|
||||
metalDisplayLinkRunLoop cocoa.NSRunLoop
|
||||
|
||||
// The following members are used only with CADisplayLink.
|
||||
handleToSelf cgo.Handle
|
||||
fence *fence
|
||||
}
|
||||
|
||||
func (v *view) setDrawableSize(width, height int) {
|
||||
@@ -58,10 +81,10 @@ func (v *view) colorPixelFormat() mtl.PixelFormat {
|
||||
return v.ml.PixelFormat()
|
||||
}
|
||||
|
||||
func (v *view) initialize(device mtl.Device) error {
|
||||
func (v *view) initialize(device mtl.Device, colorSpace graphicsdriver.ColorSpace) error {
|
||||
v.device = device
|
||||
|
||||
ml, err := ca.MakeMetalLayer()
|
||||
ml, err := ca.NewMetalLayer(colorSpace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -83,16 +106,39 @@ func (v *view) initialize(device mtl.Device) error {
|
||||
// nextDrawable took more than one second if the window has other controls like NSTextView (#1029).
|
||||
v.ml.SetPresentsWithTransaction(false)
|
||||
|
||||
v.ml.SetMaximumDrawableCount(v.maximumDrawableCount())
|
||||
v.ml.SetMaximumDrawableCount(maximumDrawableCount)
|
||||
|
||||
if err := v.initializeOS(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *view) nextDrawable() ca.MetalDrawable {
|
||||
d, err := v.ml.NextDrawable()
|
||||
if err != nil {
|
||||
// Drawable is nil. This can happen at the initial state. Let's wait and see.
|
||||
return ca.MetalDrawable{}
|
||||
}
|
||||
return d
|
||||
type fence struct {
|
||||
value uint64
|
||||
lastValue uint64
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
func newFence() *fence {
|
||||
return &fence{
|
||||
cond: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fence) wait() {
|
||||
f.cond.L.Lock()
|
||||
defer f.cond.L.Unlock()
|
||||
for f.lastValue >= f.value {
|
||||
f.cond.Wait()
|
||||
}
|
||||
f.lastValue = f.value
|
||||
}
|
||||
|
||||
func (f *fence) advance() {
|
||||
f.cond.L.Lock()
|
||||
defer f.cond.L.Unlock()
|
||||
f.value++
|
||||
f.cond.Broadcast()
|
||||
}
|
||||
|
||||
Generated
Vendored
+21
-3
@@ -22,11 +22,15 @@ package metal
|
||||
//
|
||||
// #import <UIKit/UIKit.h>
|
||||
//
|
||||
// #cgo noescape addSublayer
|
||||
// #cgo nocallback addSublayer
|
||||
// static void addSublayer(void* view, void* sublayer) {
|
||||
// CALayer* layer = ((UIView*)view).layer;
|
||||
// [layer addSublayer:(CALayer*)sublayer];
|
||||
// }
|
||||
//
|
||||
// #cgo noescape setFrame
|
||||
// #cgo nocallback setFrame
|
||||
// static void setFrame(void* cametal, void* uiview) {
|
||||
// __block CGSize size;
|
||||
// dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
@@ -39,6 +43,7 @@ import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
@@ -65,7 +70,20 @@ const (
|
||||
resourceStorageMode = mtl.ResourceStorageModeShared
|
||||
)
|
||||
|
||||
func (v *view) maximumDrawableCount() int {
|
||||
// TODO: Is 2 available for iOS?
|
||||
return 3
|
||||
func (v *view) nextDrawable() ca.MetalDrawable {
|
||||
d, err := v.ml.NextDrawable()
|
||||
if err != nil {
|
||||
// Drawable is nil. This can happen at the initial state. Let's wait and see.
|
||||
return ca.MetalDrawable{}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (v *view) finishDrawableUsage() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
func (v *view) initializeOS() error {
|
||||
// Do nothing.
|
||||
return nil
|
||||
}
|
||||
|
||||
Generated
Vendored
+15
-22
@@ -17,14 +17,14 @@
|
||||
package metal
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
const kCVReturnSuccess = 0
|
||||
|
||||
func (v *view) setWindow(window uintptr) {
|
||||
// NSView can be updated e.g., fullscreen-state is switched.
|
||||
v.window = window
|
||||
@@ -36,8 +36,6 @@ func (v *view) setUIView(uiview uintptr) {
|
||||
}
|
||||
|
||||
func (v *view) update() {
|
||||
v.ml.SetMaximumDrawableCount(v.maximumDrawableCount())
|
||||
|
||||
if !v.windowChanged {
|
||||
return
|
||||
}
|
||||
@@ -55,25 +53,20 @@ const (
|
||||
resourceStorageMode = mtl.ResourceStorageModeManaged
|
||||
)
|
||||
|
||||
func (v *view) maximumDrawableCount() int {
|
||||
// Note that the architecture might not be the true reason of the issues (#2880, #2883).
|
||||
// Hajime tested only MacBook Pro 2020 (Intel) and MacBook Pro 2023 (M3).
|
||||
|
||||
// Use 3 for Intel Mac and iOS. With 2, There are some situations that the FPS becomes half, or the FPS becomes too low (#2880).
|
||||
if runtime.GOARCH == "amd64" {
|
||||
return 3
|
||||
func (v *view) initializeOS() error {
|
||||
if err := v.initDisplayLink(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use 3 in fullscren.
|
||||
// Though this might degrade FPS, this is necessary to avoid mysterious rendering delays.
|
||||
if v.isFullscreen() {
|
||||
return 3
|
||||
}
|
||||
|
||||
// Use 2 for a Wnidow to avoid mysterious blinking (#2883).
|
||||
return 2
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *view) isFullscreen() bool {
|
||||
return cocoa.NSWindow{ID: objc.ID(v.window)}.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0
|
||||
func (v *view) waitForDisplayLinkOutputCallback() {
|
||||
if v.caDisplayLink == 0 && v.metalDisplayLink == 0 {
|
||||
return
|
||||
}
|
||||
if v.caDisplayLink == 0 && v.vsyncDisabled {
|
||||
// TODO: nextDrawable still waits for the next drawable available, so this should be fixed not to wait.
|
||||
return
|
||||
}
|
||||
v.fence.wait()
|
||||
}
|
||||
|
||||
Generated
Vendored
+62
-47
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
@@ -89,7 +90,6 @@ type (
|
||||
|
||||
type (
|
||||
uniformLocation int32
|
||||
attribLocation int32
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -100,19 +100,19 @@ const (
|
||||
type context struct {
|
||||
ctx gl.Context
|
||||
|
||||
locationCache *locationCache
|
||||
screenFramebuffer framebufferNative // This might not be the default frame buffer '0' (e.g. iOS).
|
||||
lastFramebuffer framebufferNative
|
||||
lastTexture textureNative
|
||||
lastRenderbuffer renderbufferNative
|
||||
lastViewportWidth int
|
||||
lastViewportHeight int
|
||||
lastBlend graphicsdriver.Blend
|
||||
maxTextureSize int
|
||||
maxTextureSizeOnce sync.Once
|
||||
highp bool
|
||||
highpOnce sync.Once
|
||||
initOnce sync.Once
|
||||
locationCache *locationCache
|
||||
screenFramebuffer framebufferNative // This might not be the default frame buffer '0' (e.g. iOS).
|
||||
lastFramebuffer framebufferNative
|
||||
lastTexture textureNative
|
||||
lastRenderbuffer renderbufferNative
|
||||
lastViewportWidth int
|
||||
lastViewportHeight int
|
||||
lastBlend graphicsdriver.Blend
|
||||
maxTextureSize int
|
||||
maxTextureSizeOnce sync.Once
|
||||
initOnce sync.Once
|
||||
hasKHRParallelShaderCompile bool
|
||||
hasKHRParallelShaderCompileOnce sync.Once
|
||||
}
|
||||
|
||||
func (c *context) bindTexture(t textureNative) {
|
||||
@@ -141,14 +141,14 @@ func (c *context) bindFramebuffer(f framebufferNative) {
|
||||
|
||||
func (c *context) setViewport(f *framebuffer) {
|
||||
c.bindFramebuffer(f.native)
|
||||
if c.lastViewportWidth == f.width && c.lastViewportHeight == f.height {
|
||||
if c.lastViewportWidth == f.viewportWidth && c.lastViewportHeight == f.viewportHeight {
|
||||
return
|
||||
}
|
||||
|
||||
// On some environments, viewport size must be within the framebuffer size.
|
||||
// e.g. Edge (#71), Chrome on GPD Pocket (#420), macOS Mojave (#691).
|
||||
// Use the same size of the framebuffer here.
|
||||
c.ctx.Viewport(0, 0, int32(f.width), int32(f.height))
|
||||
c.ctx.Viewport(0, 0, int32(f.viewportWidth), int32(f.viewportHeight))
|
||||
|
||||
// glViewport must be called at least at every frame on iOS.
|
||||
// As the screen framebuffer is the last render target, next SetViewport should be
|
||||
@@ -157,16 +157,16 @@ func (c *context) setViewport(f *framebuffer) {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
} else {
|
||||
c.lastViewportWidth = f.width
|
||||
c.lastViewportHeight = f.height
|
||||
c.lastViewportWidth = f.viewportWidth
|
||||
c.lastViewportHeight = f.viewportHeight
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) newScreenFramebuffer(width, height int) *framebuffer {
|
||||
return &framebuffer{
|
||||
native: c.screenFramebuffer,
|
||||
width: width,
|
||||
height: height,
|
||||
native: c.screenFramebuffer,
|
||||
viewportWidth: width,
|
||||
viewportHeight: height,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,9 +319,6 @@ func (c *context) newRenderbuffer(width, height int) (renderbufferNative, error)
|
||||
}
|
||||
|
||||
func (c *context) deleteRenderbuffer(r renderbufferNative) {
|
||||
if !c.ctx.IsRenderbuffer(uint32(r)) {
|
||||
return
|
||||
}
|
||||
if c.lastRenderbuffer == r {
|
||||
c.lastRenderbuffer = 0
|
||||
}
|
||||
@@ -336,19 +333,23 @@ func (c *context) newFramebuffer(texture textureNative, width, height int) (*fra
|
||||
c.bindFramebuffer(framebufferNative(f))
|
||||
|
||||
c.ctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(texture), 0)
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
if s != 0 {
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: %v", s)
|
||||
|
||||
if shouldCheckFramebufferStatus() {
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
if s != 0 {
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: %v", s)
|
||||
}
|
||||
if e := c.ctx.GetError(); e != gl.NO_ERROR {
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e)
|
||||
}
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: unknown error")
|
||||
}
|
||||
if e := c.ctx.GetError(); e != gl.NO_ERROR {
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e)
|
||||
}
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: unknown error")
|
||||
}
|
||||
|
||||
return &framebuffer{
|
||||
native: framebufferNative(f),
|
||||
width: width,
|
||||
height: height,
|
||||
native: framebufferNative(f),
|
||||
viewportWidth: width,
|
||||
viewportHeight: height,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -356,9 +357,13 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
|
||||
c.bindFramebuffer(f)
|
||||
|
||||
c.ctx.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, uint32(r))
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
||||
|
||||
if shouldCheckFramebufferStatus() {
|
||||
if s := c.ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||
return fmt.Errorf("opengl: glFramebufferRenderbuffer failed: %d", s)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -366,9 +371,6 @@ func (c *context) deleteFramebuffer(f framebufferNative) {
|
||||
if f == c.screenFramebuffer {
|
||||
return
|
||||
}
|
||||
if !c.ctx.IsFramebuffer(uint32(f)) {
|
||||
return
|
||||
}
|
||||
// If a framebuffer to be deleted is bound, a newly bound framebuffer
|
||||
// will be a default framebuffer.
|
||||
// https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml
|
||||
@@ -389,10 +391,6 @@ func (c *context) newShader(shaderType uint32, source string) (shader, error) {
|
||||
c.ctx.ShaderSource(s, source)
|
||||
c.ctx.CompileShader(s)
|
||||
|
||||
if c.ctx.GetShaderi(s, gl.COMPILE_STATUS) == gl.FALSE {
|
||||
log := c.ctx.GetShaderInfoLog(s)
|
||||
return 0, fmt.Errorf("opengl: shader compile failed: %s", log)
|
||||
}
|
||||
return shader(s), nil
|
||||
}
|
||||
|
||||
@@ -411,10 +409,6 @@ func (c *context) newProgram(shaders []shader, attributes []string) (program, er
|
||||
}
|
||||
|
||||
c.ctx.LinkProgram(p)
|
||||
if c.ctx.GetProgrami(p, gl.LINK_STATUS) == gl.FALSE {
|
||||
info := c.ctx.GetProgramInfoLog(p)
|
||||
return 0, fmt.Errorf("opengl: program error: %s", info)
|
||||
}
|
||||
return program(p), nil
|
||||
}
|
||||
|
||||
@@ -448,6 +442,8 @@ func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.
|
||||
}
|
||||
|
||||
switch base {
|
||||
case shaderir.Bool:
|
||||
c.ctx.Uniform1iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.Float:
|
||||
c.ctx.Uniform1fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Int:
|
||||
@@ -496,3 +492,22 @@ func (c *context) glslVersion() glsl.GLSLVersion {
|
||||
}
|
||||
return glsl.GLSLVersionDefault
|
||||
}
|
||||
|
||||
func shouldCheckFramebufferStatus() bool {
|
||||
// CheckFramebufferStatus is slow and should be avoided especially in browsers.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#avoid_blocking_api_calls_in_production
|
||||
//
|
||||
// TODO: Should this be avoided in all environments?
|
||||
return runtime.GOOS != "js"
|
||||
}
|
||||
|
||||
func (c *context) hasParallelShaderCompile() bool {
|
||||
c.hasKHRParallelShaderCompileOnce.Do(func() {
|
||||
if runtime.GOOS != "js" {
|
||||
return
|
||||
}
|
||||
ext := c.ctx.GetExtension("KHR_parallel_shader_compile")
|
||||
c.hasKHRParallelShaderCompile = ext != nil
|
||||
})
|
||||
return c.hasKHRParallelShaderCompile
|
||||
}
|
||||
|
||||
Generated
Vendored
+103
@@ -0,0 +1,103 @@
|
||||
// Copyright 2019 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
var (
|
||||
object = js.Global().Get("Object")
|
||||
arrayBuffer = js.Global().Get("ArrayBuffer")
|
||||
uint8Array = js.Global().Get("Uint8Array")
|
||||
float32Array = js.Global().Get("Float32Array")
|
||||
int32Array = js.Global().Get("Int32Array")
|
||||
)
|
||||
|
||||
var (
|
||||
tmpArrayBufferByteLength = 16
|
||||
|
||||
// tmpArrayBuffer is a temporary buffer used at gl.readPixels or gl.texSubImage2D.
|
||||
// The read data is converted to Go's byte slice as soon as possible.
|
||||
// To avoid often allocating ArrayBuffer, reuse the buffer whenever possible.
|
||||
tmpArrayBuffer = arrayBuffer.New(tmpArrayBufferByteLength)
|
||||
|
||||
// tmpUint8Array is a Uint8ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
tmpUint8Array = uint8Array.New(tmpArrayBuffer)
|
||||
|
||||
// tmpFloat32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
tmpFloat32Array = float32Array.New(tmpArrayBuffer)
|
||||
|
||||
// tmpInt32Array is a Float32ArrayBuffer whose underlying buffer is always temporaryArrayBuffer.
|
||||
tmpInt32Array = int32Array.New(tmpArrayBuffer)
|
||||
)
|
||||
|
||||
func ensureTemporaryArrayBufferSize(byteLength int) {
|
||||
if bufl := tmpArrayBufferByteLength; bufl < byteLength {
|
||||
for bufl < byteLength {
|
||||
bufl *= 2
|
||||
}
|
||||
tmpArrayBufferByteLength = bufl
|
||||
tmpArrayBuffer = arrayBuffer.New(bufl)
|
||||
tmpUint8Array = uint8Array.New(tmpArrayBuffer)
|
||||
tmpFloat32Array = float32Array.New(tmpArrayBuffer)
|
||||
tmpInt32Array = int32Array.New(tmpArrayBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
// tmpUint8ArrayFromUint8Slice returns a Uint8Array whose length is at least minLength from an uint8 slice.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func tmpUint8ArrayFromUint8Slice(minLength int, data []uint8) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength)
|
||||
copyUint8SliceToTemporaryArrayBuffer(data)
|
||||
return tmpUint8Array
|
||||
}
|
||||
|
||||
// tmpUint8ArrayFromUint16Slice returns a Uint8Array whose length is at least minLength from an uint16 slice.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func tmpUint8ArrayFromUint16Slice(minLength int, data []uint16) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 2)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return tmpUint8Array
|
||||
}
|
||||
|
||||
// tmpUint8ArrayFromFloat32Slice returns a Uint8Array whose length is at least minLength from a float32 slice.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func tmpUint8ArrayFromFloat32Slice(minLength int, data []float32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return tmpUint8Array
|
||||
}
|
||||
|
||||
// tmpFloat32ArrayFromFloat32Slice returns a Float32Array whose length is at least minLength.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func tmpFloat32ArrayFromFloat32Slice(minLength int, data []float32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return tmpFloat32Array
|
||||
}
|
||||
|
||||
// tmpInt32ArrayFromInt32Slice returns a Int32Array whose length is at least minLength.
|
||||
// Be careful that the length can exceed the given minLength.
|
||||
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
|
||||
func tmpInt32ArrayFromInt32Slice(minLength int, data []int32) js.Value {
|
||||
ensureTemporaryArrayBufferSize(minLength * 4)
|
||||
copySliceToTemporaryArrayBuffer(data)
|
||||
return tmpInt32Array
|
||||
}
|
||||
Generated
Vendored
+1
@@ -23,6 +23,7 @@ const (
|
||||
BLEND = 0x0BE2
|
||||
CLAMP_TO_EDGE = 0x812F
|
||||
COLOR_ATTACHMENT0 = 0x8CE0
|
||||
COMPLETION_STATUS_KHR = 0x91B1
|
||||
COMPILE_STATUS = 0x8B81
|
||||
DECR_WRAP = 0x8508
|
||||
DEPTH24_STENCIL8 = 0x88F0
|
||||
|
||||
Generated
Vendored
+9
-18
@@ -347,6 +347,15 @@ func (d *DebugContext) GetError() uint32 {
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetExtension(arg0 string) any {
|
||||
out0 := d.Context.GetExtension(arg0)
|
||||
fmt.Fprintln(os.Stderr, "GetExtension")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetExtension", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetInteger(arg0 uint32) int {
|
||||
out0 := d.Context.GetInteger(arg0)
|
||||
fmt.Fprintln(os.Stderr, "GetInteger")
|
||||
@@ -406,15 +415,6 @@ func (d *DebugContext) IsES() bool {
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) IsFramebuffer(arg0 uint32) bool {
|
||||
out0 := d.Context.IsFramebuffer(arg0)
|
||||
fmt.Fprintln(os.Stderr, "IsFramebuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at IsFramebuffer", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) IsProgram(arg0 uint32) bool {
|
||||
out0 := d.Context.IsProgram(arg0)
|
||||
fmt.Fprintln(os.Stderr, "IsProgram")
|
||||
@@ -424,15 +424,6 @@ func (d *DebugContext) IsProgram(arg0 uint32) bool {
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) IsRenderbuffer(arg0 uint32) bool {
|
||||
out0 := d.Context.IsRenderbuffer(arg0)
|
||||
fmt.Fprintln(os.Stderr, "IsRenderbuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at IsRenderbuffer", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) LinkProgram(arg0 uint32) {
|
||||
d.Context.LinkProgram(arg0)
|
||||
fmt.Fprintln(os.Stderr, "LinkProgram")
|
||||
|
||||
Generated
Vendored
+226
-23
@@ -2,7 +2,7 @@
|
||||
// SPDX-FileCopyrightText: 2014 Eric Woroshow
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build !darwin && !js && !windows && !playstation5
|
||||
//go:build nintendosdk
|
||||
|
||||
package gl
|
||||
|
||||
@@ -20,298 +20,505 @@ package gl
|
||||
// typedef ptrdiff_t GLintptr;
|
||||
// typedef ptrdiff_t GLsizeiptr;
|
||||
//
|
||||
// #cgo noescape glowActiveTexture
|
||||
// #cgo nocallback glowActiveTexture
|
||||
// static void glowActiveTexture(uintptr_t fnptr, GLenum texture) {
|
||||
// typedef void (*fn)(GLenum texture);
|
||||
// ((fn)(fnptr))(texture);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowAttachShader
|
||||
// #cgo nocallback glowAttachShader
|
||||
// static void glowAttachShader(uintptr_t fnptr, GLuint program, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint program, GLuint shader);
|
||||
// ((fn)(fnptr))(program, shader);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindAttribLocation
|
||||
// #cgo nocallback glowBindAttribLocation
|
||||
// static void glowBindAttribLocation(uintptr_t fnptr, GLuint program, GLuint index, const GLchar* name) {
|
||||
// typedef void (*fn)(GLuint program, GLuint index, const GLchar* name);
|
||||
// ((fn)(fnptr))(program, index, name);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindBuffer
|
||||
// #cgo nocallback glowBindBuffer
|
||||
// static void glowBindBuffer(uintptr_t fnptr, GLenum target, GLuint buffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint buffer);
|
||||
// ((fn)(fnptr))(target, buffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindFramebuffer
|
||||
// #cgo nocallback glowBindFramebuffer
|
||||
// static void glowBindFramebuffer(uintptr_t fnptr, GLenum target, GLuint framebuffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint framebuffer);
|
||||
// ((fn)(fnptr))(target, framebuffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindRenderbuffer
|
||||
// #cgo nocallback glowBindRenderbuffer
|
||||
// static void glowBindRenderbuffer(uintptr_t fnptr, GLenum target, GLuint renderbuffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint renderbuffer);
|
||||
// ((fn)(fnptr))(target, renderbuffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindTexture
|
||||
// #cgo nocallback glowBindTexture
|
||||
// static void glowBindTexture(uintptr_t fnptr, GLenum target, GLuint texture) {
|
||||
// typedef void (*fn)(GLenum target, GLuint texture);
|
||||
// ((fn)(fnptr))(target, texture);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBindVertexArray
|
||||
// #cgo nocallback glowBindVertexArray
|
||||
// static void glowBindVertexArray(uintptr_t fnptr, GLuint array) {
|
||||
// typedef void (*fn)(GLuint array);
|
||||
// ((fn)(fnptr))(array);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBlendEquationSeparate
|
||||
// #cgo nocallback glowBlendEquationSeparate
|
||||
// static void glowBlendEquationSeparate(uintptr_t fnptr, GLenum modeRGB, GLenum modeAlpha) {
|
||||
// typedef void (*fn)(GLenum modeRGB, GLenum modeAlpha);
|
||||
// ((fn)(fnptr))(modeRGB, modeAlpha);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBlendFuncSeparate
|
||||
// #cgo nocallback glowBlendFuncSeparate
|
||||
// static void glowBlendFuncSeparate(uintptr_t fnptr, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
// typedef void (*fn)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
// ((fn)(fnptr))(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBufferData
|
||||
// #cgo nocallback glowBufferData
|
||||
// static void glowBufferData(uintptr_t fnptr, GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
// typedef void (*fn)(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
// ((fn)(fnptr))(target, size, data, usage);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowBufferSubData
|
||||
// #cgo nocallback glowBufferSubData
|
||||
// static void glowBufferSubData(uintptr_t fnptr, GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
|
||||
// typedef void (*fn)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
// ((fn)(fnptr))(target, offset, size, data);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowCheckFramebufferStatus
|
||||
// #cgo nocallback glowCheckFramebufferStatus
|
||||
// static GLenum glowCheckFramebufferStatus(uintptr_t fnptr, GLenum target) {
|
||||
// typedef GLenum (*fn)(GLenum target);
|
||||
// return ((fn)(fnptr))(target);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowClear
|
||||
// #cgo nocallback glowClear
|
||||
// static void glowClear(uintptr_t fnptr, GLbitfield mask) {
|
||||
// typedef void (*fn)(GLbitfield mask);
|
||||
// ((fn)(fnptr))(mask);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowColorMask
|
||||
// #cgo nocallback glowColorMask
|
||||
// static void glowColorMask(uintptr_t fnptr, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
// typedef void (*fn)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
// ((fn)(fnptr))(red, green, blue, alpha);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowCompileShader
|
||||
// #cgo nocallback glowCompileShader
|
||||
// static void glowCompileShader(uintptr_t fnptr, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint shader);
|
||||
// ((fn)(fnptr))(shader);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowCreateProgram
|
||||
// #cgo nocallback glowCreateProgram
|
||||
// static GLuint glowCreateProgram(uintptr_t fnptr) {
|
||||
// typedef GLuint (*fn)();
|
||||
// return ((fn)(fnptr))();
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowCreateShader
|
||||
// #cgo nocallback glowCreateShader
|
||||
// static GLuint glowCreateShader(uintptr_t fnptr, GLenum type) {
|
||||
// typedef GLuint (*fn)(GLenum type);
|
||||
// return ((fn)(fnptr))(type);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteBuffers
|
||||
// #cgo nocallback glowDeleteBuffers
|
||||
// static void glowDeleteBuffers(uintptr_t fnptr, GLsizei n, const GLuint* buffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* buffers);
|
||||
// ((fn)(fnptr))(n, buffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteFramebuffers
|
||||
// #cgo nocallback glowDeleteFramebuffers
|
||||
// static void glowDeleteFramebuffers(uintptr_t fnptr, GLsizei n, const GLuint* framebuffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* framebuffers);
|
||||
// ((fn)(fnptr))(n, framebuffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteProgram
|
||||
// #cgo nocallback glowDeleteProgram
|
||||
// static void glowDeleteProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteRenderbuffers
|
||||
// #cgo nocallback glowDeleteRenderbuffers
|
||||
// static void glowDeleteRenderbuffers(uintptr_t fnptr, GLsizei n, const GLuint* renderbuffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* renderbuffers);
|
||||
// ((fn)(fnptr))(n, renderbuffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteShader
|
||||
// #cgo nocallback glowDeleteShader
|
||||
// static void glowDeleteShader(uintptr_t fnptr, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint shader);
|
||||
// ((fn)(fnptr))(shader);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteTextures
|
||||
// #cgo nocallback glowDeleteTextures
|
||||
// static void glowDeleteTextures(uintptr_t fnptr, GLsizei n, const GLuint* textures) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* textures);
|
||||
// ((fn)(fnptr))(n, textures);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDeleteVertexArrays
|
||||
// #cgo nocallback glowDeleteVertexArrays
|
||||
// static void glowDeleteVertexArrays(uintptr_t fnptr, GLsizei n, const GLuint* arrays) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* arrays);
|
||||
// ((fn)(fnptr))(n, arrays);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDisable
|
||||
// #cgo nocallback glowDisable
|
||||
// static void glowDisable(uintptr_t fnptr, GLenum cap) {
|
||||
// typedef void (*fn)(GLenum cap);
|
||||
// ((fn)(fnptr))(cap);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDisableVertexAttribArray
|
||||
// #cgo nocallback glowDisableVertexAttribArray
|
||||
// static void glowDisableVertexAttribArray(uintptr_t fnptr, GLuint index) {
|
||||
// typedef void (*fn)(GLuint index);
|
||||
// ((fn)(fnptr))(index);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowDrawElements
|
||||
// #cgo nocallback glowDrawElements
|
||||
// static void glowDrawElements(uintptr_t fnptr, GLenum mode, GLsizei count, GLenum type, const uintptr_t indices) {
|
||||
// typedef void (*fn)(GLenum mode, GLsizei count, GLenum type, const uintptr_t indices);
|
||||
// ((fn)(fnptr))(mode, count, type, indices);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowEnable
|
||||
// #cgo nocallback glowEnable
|
||||
// static void glowEnable(uintptr_t fnptr, GLenum cap) {
|
||||
// typedef void (*fn)(GLenum cap);
|
||||
// ((fn)(fnptr))(cap);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowEnableVertexAttribArray
|
||||
// #cgo nocallback glowEnableVertexAttribArray
|
||||
// static void glowEnableVertexAttribArray(uintptr_t fnptr, GLuint index) {
|
||||
// typedef void (*fn)(GLuint index);
|
||||
// ((fn)(fnptr))(index);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowFlush
|
||||
// #cgo nocallback glowFlush
|
||||
// static void glowFlush(uintptr_t fnptr) {
|
||||
// typedef void (*fn)();
|
||||
// ((fn)(fnptr))();
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowFramebufferRenderbuffer
|
||||
// #cgo nocallback glowFramebufferRenderbuffer
|
||||
// static void glowFramebufferRenderbuffer(uintptr_t fnptr, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
|
||||
// typedef void (*fn)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
// ((fn)(fnptr))(target, attachment, renderbuffertarget, renderbuffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowFramebufferTexture2D
|
||||
// #cgo nocallback glowFramebufferTexture2D
|
||||
// static void glowFramebufferTexture2D(uintptr_t fnptr, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
|
||||
// typedef void (*fn)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
// ((fn)(fnptr))(target, attachment, textarget, texture, level);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGenBuffers
|
||||
// #cgo nocallback glowGenBuffers
|
||||
// static void glowGenBuffers(uintptr_t fnptr, GLsizei n, GLuint* buffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* buffers);
|
||||
// ((fn)(fnptr))(n, buffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGenFramebuffers
|
||||
// #cgo nocallback glowGenFramebuffers
|
||||
// static void glowGenFramebuffers(uintptr_t fnptr, GLsizei n, GLuint* framebuffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* framebuffers);
|
||||
// ((fn)(fnptr))(n, framebuffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGenRenderbuffers
|
||||
// #cgo nocallback glowGenRenderbuffers
|
||||
// static void glowGenRenderbuffers(uintptr_t fnptr, GLsizei n, GLuint* renderbuffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* renderbuffers);
|
||||
// ((fn)(fnptr))(n, renderbuffers);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGenTextures
|
||||
// #cgo nocallback glowGenTextures
|
||||
// static void glowGenTextures(uintptr_t fnptr, GLsizei n, GLuint* textures) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* textures);
|
||||
// ((fn)(fnptr))(n, textures);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGenVertexArrays
|
||||
// #cgo nocallback glowGenVertexArrays
|
||||
// static void glowGenVertexArrays(uintptr_t fnptr, GLsizei n, GLuint* arrays) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* arrays);
|
||||
// ((fn)(fnptr))(n, arrays);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetError
|
||||
// #cgo nocallback glowGetError
|
||||
// static GLenum glowGetError(uintptr_t fnptr) {
|
||||
// typedef GLenum (*fn)();
|
||||
// return ((fn)(fnptr))();
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetIntegerv
|
||||
// #cgo nocallback glowGetIntegerv
|
||||
// static void glowGetIntegerv(uintptr_t fnptr, GLenum pname, GLint* data) {
|
||||
// typedef void (*fn)(GLenum pname, GLint* data);
|
||||
// ((fn)(fnptr))(pname, data);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetProgramInfoLog
|
||||
// #cgo nocallback glowGetProgramInfoLog
|
||||
// static void glowGetProgramInfoLog(uintptr_t fnptr, GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
|
||||
// typedef void (*fn)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
// ((fn)(fnptr))(program, bufSize, length, infoLog);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetProgramiv
|
||||
// #cgo nocallback glowGetProgramiv
|
||||
// static void glowGetProgramiv(uintptr_t fnptr, GLuint program, GLenum pname, GLint* params) {
|
||||
// typedef void (*fn)(GLuint program, GLenum pname, GLint* params);
|
||||
// ((fn)(fnptr))(program, pname, params);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetShaderInfoLog
|
||||
// #cgo nocallback glowGetShaderInfoLog
|
||||
// static void glowGetShaderInfoLog(uintptr_t fnptr, GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
|
||||
// typedef void (*fn)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
// ((fn)(fnptr))(shader, bufSize, length, infoLog);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetShaderiv
|
||||
// #cgo nocallback glowGetShaderiv
|
||||
// static void glowGetShaderiv(uintptr_t fnptr, GLuint shader, GLenum pname, GLint* params) {
|
||||
// typedef void (*fn)(GLuint shader, GLenum pname, GLint* params);
|
||||
// ((fn)(fnptr))(shader, pname, params);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowGetUniformLocation
|
||||
// #cgo nocallback glowGetUniformLocation
|
||||
// static GLint glowGetUniformLocation(uintptr_t fnptr, GLuint program, const GLchar* name) {
|
||||
// typedef GLint (*fn)(GLuint program, const GLchar* name);
|
||||
// return ((fn)(fnptr))(program, name);
|
||||
// }
|
||||
// static GLboolean glowIsFramebuffer(uintptr_t fnptr, GLuint framebuffer) {
|
||||
// typedef GLboolean (*fn)(GLuint framebuffer);
|
||||
// return ((fn)(fnptr))(framebuffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowIsProgram
|
||||
// #cgo nocallback glowIsProgram
|
||||
// static GLboolean glowIsProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef GLboolean (*fn)(GLuint program);
|
||||
// return ((fn)(fnptr))(program);
|
||||
// }
|
||||
// static GLboolean glowIsRenderbuffer(uintptr_t fnptr, GLuint renderbuffer) {
|
||||
// typedef GLboolean (*fn)(GLuint renderbuffer);
|
||||
// return ((fn)(fnptr))(renderbuffer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowLinkProgram
|
||||
// #cgo nocallback glowLinkProgram
|
||||
// static void glowLinkProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowPixelStorei
|
||||
// #cgo nocallback glowPixelStorei
|
||||
// static void glowPixelStorei(uintptr_t fnptr, GLenum pname, GLint param) {
|
||||
// typedef void (*fn)(GLenum pname, GLint param);
|
||||
// ((fn)(fnptr))(pname, param);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowReadPixels
|
||||
// #cgo nocallback glowReadPixels
|
||||
// static void glowReadPixels(uintptr_t fnptr, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
|
||||
// typedef void (*fn)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
// ((fn)(fnptr))(x, y, width, height, format, type, pixels);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowRenderbufferStorage
|
||||
// #cgo nocallback glowRenderbufferStorage
|
||||
// static void glowRenderbufferStorage(uintptr_t fnptr, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
// typedef void (*fn)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
// ((fn)(fnptr))(target, internalformat, width, height);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowScissor
|
||||
// #cgo nocallback glowScissor
|
||||
// static void glowScissor(uintptr_t fnptr, GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
// typedef void (*fn)(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
// ((fn)(fnptr))(x, y, width, height);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowShaderSource
|
||||
// #cgo nocallback glowShaderSource
|
||||
// static void glowShaderSource(uintptr_t fnptr, GLuint shader, GLsizei count, const GLchar*const* string, const GLint* length) {
|
||||
// typedef void (*fn)(GLuint shader, GLsizei count, const GLchar*const* string, const GLint* length);
|
||||
// ((fn)(fnptr))(shader, count, string, length);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowStencilFunc
|
||||
// #cgo nocallback glowStencilFunc
|
||||
// static void glowStencilFunc(uintptr_t fnptr, GLenum func, GLint ref, GLuint mask) {
|
||||
// typedef void (*fn)(GLenum func, GLint ref, GLuint mask);
|
||||
// ((fn)(fnptr))(func, ref, mask);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowStencilOpSeparate
|
||||
// #cgo nocallback glowStencilOpSeparate
|
||||
// static void glowStencilOpSeparate(uintptr_t fnptr, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
|
||||
// typedef void (*fn)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
|
||||
// ((fn)(fnptr))(face, fail, zfail, zpass);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowTexImage2D
|
||||
// #cgo nocallback glowTexImage2D
|
||||
// static void glowTexImage2D(uintptr_t fnptr, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) {
|
||||
// typedef void (*fn)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
|
||||
// ((fn)(fnptr))(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowTexParameteri
|
||||
// #cgo nocallback glowTexParameteri
|
||||
// static void glowTexParameteri(uintptr_t fnptr, GLenum target, GLenum pname, GLint param) {
|
||||
// typedef void (*fn)(GLenum target, GLenum pname, GLint param);
|
||||
// ((fn)(fnptr))(target, pname, param);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowTexSubImage2D
|
||||
// #cgo nocallback glowTexSubImage2D
|
||||
// static void glowTexSubImage2D(uintptr_t fnptr, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) {
|
||||
// typedef void (*fn)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
|
||||
// ((fn)(fnptr))(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform1fv
|
||||
// #cgo nocallback glowUniform1fv
|
||||
// static void glowUniform1fv(uintptr_t fnptr, GLint location, GLsizei count, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform1i
|
||||
// #cgo nocallback glowUniform1i
|
||||
// static void glowUniform1i(uintptr_t fnptr, GLint location, GLint v0) {
|
||||
// typedef void (*fn)(GLint location, GLint v0);
|
||||
// ((fn)(fnptr))(location, v0);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform1iv
|
||||
// #cgo nocallback glowUniform1iv
|
||||
// static void glowUniform1iv(uintptr_t fnptr, GLint location, GLsizei count, const GLint* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLint* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform2fv
|
||||
// #cgo nocallback glowUniform2fv
|
||||
// static void glowUniform2fv(uintptr_t fnptr, GLint location, GLsizei count, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform2iv
|
||||
// #cgo nocallback glowUniform2iv
|
||||
// static void glowUniform2iv(uintptr_t fnptr, GLint location, GLsizei count, const GLint* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLint* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform3fv
|
||||
// #cgo nocallback glowUniform3fv
|
||||
// static void glowUniform3fv(uintptr_t fnptr, GLint location, GLsizei count, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform3iv
|
||||
// #cgo nocallback glowUniform3iv
|
||||
// static void glowUniform3iv(uintptr_t fnptr, GLint location, GLsizei count, const GLint* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLint* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform4fv
|
||||
// #cgo nocallback glowUniform4fv
|
||||
// static void glowUniform4fv(uintptr_t fnptr, GLint location, GLsizei count, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniform4iv
|
||||
// #cgo nocallback glowUniform4iv
|
||||
// static void glowUniform4iv(uintptr_t fnptr, GLint location, GLsizei count, const GLint* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, const GLint* value);
|
||||
// ((fn)(fnptr))(location, count, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniformMatrix2fv
|
||||
// #cgo nocallback glowUniformMatrix2fv
|
||||
// static void glowUniformMatrix2fv(uintptr_t fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, transpose, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniformMatrix3fv
|
||||
// #cgo nocallback glowUniformMatrix3fv
|
||||
// static void glowUniformMatrix3fv(uintptr_t fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, transpose, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUniformMatrix4fv
|
||||
// #cgo nocallback glowUniformMatrix4fv
|
||||
// static void glowUniformMatrix4fv(uintptr_t fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
// typedef void (*fn)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
// ((fn)(fnptr))(location, count, transpose, value);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowUseProgram
|
||||
// #cgo nocallback glowUseProgram
|
||||
// static void glowUseProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowVertexAttribPointer
|
||||
// #cgo nocallback glowVertexAttribPointer
|
||||
// static void glowVertexAttribPointer(uintptr_t fnptr, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const uintptr_t pointer) {
|
||||
// typedef void (*fn)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const uintptr_t pointer);
|
||||
// ((fn)(fnptr))(index, size, type, normalized, stride, pointer);
|
||||
// }
|
||||
//
|
||||
// #cgo noescape glowViewport
|
||||
// #cgo nocallback glowViewport
|
||||
// static void glowViewport(uintptr_t fnptr, GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
// typedef void (*fn)(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
// ((fn)(fnptr))(x, y, width, height);
|
||||
@@ -369,9 +576,7 @@ type defaultContext struct {
|
||||
gpGetShaderInfoLog C.uintptr_t
|
||||
gpGetShaderiv C.uintptr_t
|
||||
gpGetUniformLocation C.uintptr_t
|
||||
gpIsFramebuffer C.uintptr_t
|
||||
gpIsProgram C.uintptr_t
|
||||
gpIsRenderbuffer C.uintptr_t
|
||||
gpLinkProgram C.uintptr_t
|
||||
gpPixelStorei C.uintptr_t
|
||||
gpReadPixels C.uintptr_t
|
||||
@@ -594,6 +799,10 @@ func (c *defaultContext) GetError() uint32 {
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetExtension(name string) any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
var dst int32
|
||||
C.glowGetIntegerv(c.gpGetIntegerv, C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst)))
|
||||
@@ -602,6 +811,9 @@ func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
|
||||
if bufSize == 0 {
|
||||
return ""
|
||||
}
|
||||
infoLog := make([]byte, bufSize)
|
||||
C.glowGetProgramInfoLog(c.gpGetProgramInfoLog, C.GLuint(program), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
@@ -615,6 +827,9 @@ func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
|
||||
if bufSize == 0 {
|
||||
return ""
|
||||
}
|
||||
infoLog := make([]byte, bufSize)
|
||||
C.glowGetShaderInfoLog(c.gpGetShaderInfoLog, C.GLuint(shader), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
@@ -633,21 +848,11 @@ func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
return int32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsFramebuffer(framebuffer uint32) bool {
|
||||
ret := C.glowIsFramebuffer(c.gpIsFramebuffer, C.GLuint(framebuffer))
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsProgram(program uint32) bool {
|
||||
ret := C.glowIsProgram(c.gpIsProgram, C.GLuint(program))
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsRenderbuffer(renderbuffer uint32) bool {
|
||||
ret := C.glowIsRenderbuffer(c.gpIsRenderbuffer, C.GLuint(renderbuffer))
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func (c *defaultContext) LinkProgram(program uint32) {
|
||||
C.glowLinkProgram(c.gpLinkProgram, C.GLuint(program))
|
||||
}
|
||||
@@ -819,9 +1024,7 @@ func (c *defaultContext) LoadFunctions() error {
|
||||
c.gpGetShaderInfoLog = C.uintptr_t(g.get("glGetShaderInfoLog"))
|
||||
c.gpGetShaderiv = C.uintptr_t(g.get("glGetShaderiv"))
|
||||
c.gpGetUniformLocation = C.uintptr_t(g.get("glGetUniformLocation"))
|
||||
c.gpIsFramebuffer = C.uintptr_t(g.get("glIsFramebuffer"))
|
||||
c.gpIsProgram = C.uintptr_t(g.get("glIsProgram"))
|
||||
c.gpIsRenderbuffer = C.uintptr_t(g.get("glIsRenderbuffer"))
|
||||
c.gpLinkProgram = C.uintptr_t(g.get("glLinkProgram"))
|
||||
c.gpPixelStorei = C.uintptr_t(g.get("glPixelStorei"))
|
||||
c.gpReadPixels = C.uintptr_t(g.get("glReadPixels"))
|
||||
|
||||
Generated
Vendored
+25
-29
@@ -17,8 +17,6 @@ package gl
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/jsutil"
|
||||
)
|
||||
|
||||
type defaultContext struct {
|
||||
@@ -61,15 +59,14 @@ type defaultContext struct {
|
||||
fnFramebufferTexture2D js.Value
|
||||
fnFlush js.Value
|
||||
fnGetError js.Value
|
||||
fnGetExtension js.Value
|
||||
fnGetParameter js.Value
|
||||
fnGetProgramInfoLog js.Value
|
||||
fnGetProgramParameter js.Value
|
||||
fnGetShaderInfoLog js.Value
|
||||
fnGetShaderParameter js.Value
|
||||
fnGetUniformLocation js.Value
|
||||
fnIsFramebuffer js.Value
|
||||
fnIsProgram js.Value
|
||||
fnIsRenderbuffer js.Value
|
||||
fnLinkProgram js.Value
|
||||
fnPixelStorei js.Value
|
||||
fnReadPixels js.Value
|
||||
@@ -191,15 +188,14 @@ func NewDefaultContext(v js.Value) (Context, error) {
|
||||
fnFramebufferTexture2D: v.Get("framebufferTexture2D").Call("bind", v),
|
||||
fnFlush: v.Get("flush").Call("bind", v),
|
||||
fnGetError: v.Get("getError").Call("bind", v),
|
||||
fnGetExtension: v.Get("getExtension").Call("bind", v),
|
||||
fnGetParameter: v.Get("getParameter").Call("bind", v),
|
||||
fnGetProgramInfoLog: v.Get("getProgramInfoLog").Call("bind", v),
|
||||
fnGetProgramParameter: v.Get("getProgramParameter").Call("bind", v),
|
||||
fnGetShaderInfoLog: v.Get("getShaderInfoLog").Call("bind", v),
|
||||
fnGetShaderParameter: v.Get("getShaderParameter").Call("bind", v),
|
||||
fnGetUniformLocation: v.Get("getUniformLocation").Call("bind", v),
|
||||
fnIsFramebuffer: v.Get("isFramebuffer").Call("bind", v),
|
||||
fnIsProgram: v.Get("isProgram").Call("bind", v),
|
||||
fnIsRenderbuffer: v.Get("isRenderbuffer").Call("bind", v),
|
||||
fnLinkProgram: v.Get("linkProgram").Call("bind", v),
|
||||
fnPixelStorei: v.Get("pixelStorei").Call("bind", v),
|
||||
fnReadPixels: v.Get("readPixels").Call("bind", v),
|
||||
@@ -292,7 +288,7 @@ func (c *defaultContext) BufferInit(target uint32, size int, usage uint32) {
|
||||
|
||||
func (c *defaultContext) BufferSubData(target uint32, offset int, data []byte) {
|
||||
l := len(data)
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(l, data)
|
||||
arr := tmpUint8ArrayFromUint8Slice(l, data)
|
||||
c.fnBufferSubData.Invoke(target, offset, arr, 0, l)
|
||||
}
|
||||
|
||||
@@ -373,7 +369,7 @@ func (c *defaultContext) DeleteTexture(texture uint32) {
|
||||
|
||||
func (c *defaultContext) DeleteVertexArray(array uint32) {
|
||||
c.fnDeleteVertexArray.Invoke(c.vertexArrays.get(array))
|
||||
c.textures.delete(array)
|
||||
c.vertexArrays.delete(array)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Disable(cap uint32) {
|
||||
@@ -412,6 +408,14 @@ func (c *defaultContext) GetError() uint32 {
|
||||
return uint32(c.fnGetError.Invoke().Int())
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetExtension(name string) any {
|
||||
ext := c.fnGetExtension.Invoke(name)
|
||||
if ext.IsNull() || ext.IsUndefined() {
|
||||
return nil
|
||||
}
|
||||
return ext
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
ret := c.fnGetParameter.Invoke(pname)
|
||||
switch pname {
|
||||
@@ -481,18 +485,10 @@ func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
return int32((program << 5) | idx)
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsFramebuffer(framebuffer uint32) bool {
|
||||
return c.fnIsFramebuffer.Invoke(c.framebuffers.get(framebuffer)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsProgram(program uint32) bool {
|
||||
return c.fnIsProgram.Invoke(c.programs.get(program)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsRenderbuffer(renderbuffer uint32) bool {
|
||||
return c.fnIsRenderbuffer.Invoke(c.renderbuffers.get(renderbuffer)).Bool()
|
||||
}
|
||||
|
||||
func (c *defaultContext) LinkProgram(program uint32) {
|
||||
c.fnLinkProgram.Invoke(c.programs.get(program))
|
||||
}
|
||||
@@ -506,7 +502,7 @@ func (c *defaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, h
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, 0)
|
||||
return
|
||||
}
|
||||
p := jsutil.TemporaryUint8ArrayFromUint8Slice(len(dst), nil)
|
||||
p := tmpUint8ArrayFromUint8Slice(len(dst), nil)
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, p)
|
||||
js.CopyBytesToGo(dst, p)
|
||||
}
|
||||
@@ -543,7 +539,7 @@ func (c *defaultContext) TexParameteri(target uint32, pname uint32, param int32)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(len(pixels), pixels)
|
||||
arr := tmpUint8ArrayFromUint8Slice(len(pixels), pixels)
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView pixels, srcOffset);
|
||||
@@ -552,7 +548,7 @@ func (c *defaultContext) TexSubImage2D(target uint32, level int32, xoffset int32
|
||||
|
||||
func (c *defaultContext) Uniform1fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniform1fv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
@@ -563,61 +559,61 @@ func (c *defaultContext) Uniform1i(location int32, v0 int32) {
|
||||
|
||||
func (c *defaultContext) Uniform1iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(len(value), value)
|
||||
arr := tmpInt32ArrayFromInt32Slice(len(value), value)
|
||||
c.fnUniform1iv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniform2fv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(len(value), value)
|
||||
arr := tmpInt32ArrayFromInt32Slice(len(value), value)
|
||||
c.fnUniform2iv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniform3fv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(len(value), value)
|
||||
arr := tmpInt32ArrayFromInt32Slice(len(value), value)
|
||||
c.fnUniform3iv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniform4fv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(len(value), value)
|
||||
arr := tmpInt32ArrayFromInt32Slice(len(value), value)
|
||||
c.fnUniform4iv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniformMatrix2fv.Invoke(l, false, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix3fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniformMatrix3fv.Invoke(l, false, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix4fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
arr := tmpFloat32ArrayFromFloat32Slice(len(value), value)
|
||||
c.fnUniformMatrix4fv.Invoke(l, false, arr, 0, len(value))
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+11
-15
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build darwin || windows
|
||||
//go:build (darwin || freebsd || linux || netbsd || openbsd || windows) && !nintendosdk && !playstation5
|
||||
|
||||
package gl
|
||||
|
||||
@@ -69,9 +69,7 @@ type defaultContext struct {
|
||||
gpGetShaderInfoLog uintptr
|
||||
gpGetShaderiv uintptr
|
||||
gpGetUniformLocation uintptr
|
||||
gpIsFramebuffer uintptr
|
||||
gpIsProgram uintptr
|
||||
gpIsRenderbuffer uintptr
|
||||
gpLinkProgram uintptr
|
||||
gpPixelStorei uintptr
|
||||
gpReadPixels uintptr
|
||||
@@ -294,6 +292,10 @@ func (c *defaultContext) GetError() uint32 {
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetExtension(name string) any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
var dst int32
|
||||
purego.SyscallN(c.gpGetIntegerv, uintptr(pname), uintptr(unsafe.Pointer(&dst)))
|
||||
@@ -302,6 +304,9 @@ func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
|
||||
if bufSize == 0 {
|
||||
return ""
|
||||
}
|
||||
infoLog := make([]byte, bufSize)
|
||||
purego.SyscallN(c.gpGetProgramInfoLog, uintptr(program), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
@@ -315,6 +320,9 @@ func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
|
||||
if bufSize == 0 {
|
||||
return ""
|
||||
}
|
||||
infoLog := make([]byte, bufSize)
|
||||
purego.SyscallN(c.gpGetShaderInfoLog, uintptr(shader), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
@@ -333,21 +341,11 @@ func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
return int32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsFramebuffer(framebuffer uint32) bool {
|
||||
ret, _, _ := purego.SyscallN(c.gpIsFramebuffer, uintptr(framebuffer))
|
||||
return byte(ret) != 0
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsProgram(program uint32) bool {
|
||||
ret, _, _ := purego.SyscallN(c.gpIsProgram, uintptr(program))
|
||||
return byte(ret) != 0
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsRenderbuffer(renderbuffer uint32) bool {
|
||||
ret, _, _ := purego.SyscallN(c.gpIsRenderbuffer, uintptr(renderbuffer))
|
||||
return byte(ret) != 0
|
||||
}
|
||||
|
||||
func (c *defaultContext) LinkProgram(program uint32) {
|
||||
purego.SyscallN(c.gpLinkProgram, uintptr(program))
|
||||
}
|
||||
@@ -519,9 +517,7 @@ func (c *defaultContext) LoadFunctions() error {
|
||||
c.gpGetShaderInfoLog = g.get("glGetShaderInfoLog")
|
||||
c.gpGetShaderiv = g.get("glGetShaderiv")
|
||||
c.gpGetUniformLocation = g.get("glGetUniformLocation")
|
||||
c.gpIsFramebuffer = g.get("glIsFramebuffer")
|
||||
c.gpIsProgram = g.get("glIsProgram")
|
||||
c.gpIsRenderbuffer = g.get("glIsRenderbuffer")
|
||||
c.gpLinkProgram = g.get("glLinkProgram")
|
||||
c.gpPixelStorei = g.get("glPixelStorei")
|
||||
c.gpReadPixels = g.get("glReadPixels")
|
||||
|
||||
Generated
Vendored
+1
-2
@@ -66,15 +66,14 @@ type Context interface {
|
||||
FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32)
|
||||
FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32)
|
||||
GetError() uint32
|
||||
GetExtension(name string) any
|
||||
GetInteger(pname uint32) int
|
||||
GetProgramInfoLog(program uint32) string
|
||||
GetProgrami(program uint32, pname uint32) int
|
||||
GetShaderInfoLog(shader uint32) string
|
||||
GetShaderi(shader uint32, pname uint32) int
|
||||
GetUniformLocation(program uint32, name string) int32
|
||||
IsFramebuffer(framebuffer uint32) bool
|
||||
IsProgram(program uint32) bool
|
||||
IsRenderbuffer(renderbuffer uint32) bool
|
||||
LinkProgram(program uint32)
|
||||
PixelStorei(pname uint32, param int32)
|
||||
ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32)
|
||||
|
||||
Generated
Vendored
+1
-2
@@ -38,8 +38,7 @@ func (c *defaultContext) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Use multiple %w-s as of Go 1.20
|
||||
return fmt.Errorf("gl: failed to load: OpenGL.framework: %v, OpenGLES.framework: %v", errGL, errGLES)
|
||||
return fmt.Errorf("gl: failed to load: OpenGL.framework: %w, OpenGLES.framework: %w", errGL, errGLES)
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(name string) (uintptr, error) {
|
||||
|
||||
Generated
Vendored
+52
-67
@@ -16,99 +16,84 @@
|
||||
|
||||
package gl
|
||||
|
||||
// #cgo LDFLAGS: -ldl
|
||||
//
|
||||
// #include <dlfcn.h>
|
||||
// #include <stdlib.h>
|
||||
//
|
||||
// static void* getProcAddressGL(void* libGL, const char* name) {
|
||||
// static void*(*glXGetProcAddress)(const char*);
|
||||
// if (!glXGetProcAddress) {
|
||||
// glXGetProcAddress = dlsym(libGL, "glXGetProcAddress");
|
||||
// if (!glXGetProcAddress) {
|
||||
// glXGetProcAddress = dlsym(libGL, "glXGetProcAddressARB");
|
||||
// }
|
||||
// }
|
||||
// return glXGetProcAddress(name);
|
||||
// }
|
||||
//
|
||||
// static void* getProcAddressGLES(void* libGLES, const char* name) {
|
||||
// return dlsym(libGLES, name);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
var (
|
||||
libGL unsafe.Pointer
|
||||
libGLES unsafe.Pointer
|
||||
libGL uintptr
|
||||
libGLES uintptr
|
||||
)
|
||||
|
||||
func (c *defaultContext) init() error {
|
||||
var preferES bool
|
||||
if runtime.GOOS == "android" {
|
||||
preferES = true
|
||||
}
|
||||
if !preferES {
|
||||
for _, t := range strings.Split(os.Getenv("EBITENGINE_OPENGL"), ",") {
|
||||
switch strings.TrimSpace(t) {
|
||||
case "es":
|
||||
preferES = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
var errs []error
|
||||
|
||||
// Try OpenGL first. OpenGL is preferable as this doesn't cause context losses.
|
||||
if !preferES {
|
||||
// Usually libGL.so or libGL.so.1 is used. libGL.so.2 might exist only on NetBSD.
|
||||
for _, name := range []string{"libGL.so", "libGL.so.2", "libGL.so.1", "libGL.so.0"} {
|
||||
cname := C.CString(name)
|
||||
lib := C.dlopen(cname, C.RTLD_LAZY|C.RTLD_GLOBAL)
|
||||
C.free(unsafe.Pointer(cname))
|
||||
if lib != nil {
|
||||
libGL = lib
|
||||
// Try OpenGL ES first. Some machines like Android and Raspberry Pi might work only with OpenGL ES.
|
||||
//
|
||||
// Do not use OpenGL ES for Steam, as overlays might not work properly (#3338).
|
||||
// With Steam, OpenGL (not ES) should be available anyway.
|
||||
if os.Getenv("SteamEnv") != "1" {
|
||||
for _, name := range []string{"libGLESv2.so", "libGLESv2.so.2", "libGLESv2.so.1", "libGLESv2.so.0"} {
|
||||
lib, err := purego.Dlopen(name, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err == nil {
|
||||
libGLES = lib
|
||||
c.isES = true
|
||||
return nil
|
||||
}
|
||||
errs = append(errs, fmt.Errorf("gl: Dlopen failed: name: %s: %w", name, err))
|
||||
}
|
||||
}
|
||||
|
||||
// Try OpenGL ES.
|
||||
for _, name := range []string{"libGLESv2.so", "libGLESv2.so.2", "libGLESv2.so.1", "libGLESv2.so.0"} {
|
||||
cname := C.CString(name)
|
||||
lib := C.dlopen(cname, C.RTLD_LAZY|C.RTLD_GLOBAL)
|
||||
C.free(unsafe.Pointer(cname))
|
||||
if lib != nil {
|
||||
libGLES = lib
|
||||
c.isES = true
|
||||
// Try OpenGL next.
|
||||
// Usually libGL.so or libGL.so.1 is used. libGL.so.2 might exist only on NetBSD.
|
||||
// TODO: Should "libOpenGL.so.0" [1] and "libGLX.so.0" [2] be added? These were added as of GLFW 3.3.9.
|
||||
// [1] https://github.com/glfw/glfw/commit/55aad3c37b67f17279378db52da0a3ab81bbf26d
|
||||
// [2] https://github.com/glfw/glfw/commit/c18851f52ec9704eb06464058a600845ec1eada1
|
||||
for _, name := range []string{"libGL.so", "libGL.so.2", "libGL.so.1", "libGL.so.0"} {
|
||||
lib, err := purego.Dlopen(name, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err == nil {
|
||||
libGL = lib
|
||||
return nil
|
||||
}
|
||||
errs = append(errs, fmt.Errorf("gl: Dlopen failed: name: %s: %w", name, err))
|
||||
}
|
||||
|
||||
return fmt.Errorf("gl: failed to load libGL.so and libGLESv2.so")
|
||||
errs = append([]error{fmt.Errorf("gl: failed to load libGL.so and libGLESv2.so: ")}, errs...)
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(name string) (uintptr, error) {
|
||||
if c.isES {
|
||||
return getProcAddressGLES(name), nil
|
||||
return getProcAddressGLES(name)
|
||||
}
|
||||
return getProcAddressGL(name), nil
|
||||
return getProcAddressGL(name)
|
||||
}
|
||||
|
||||
func getProcAddressGL(name string) uintptr {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return uintptr(C.getProcAddressGL(libGL, cname))
|
||||
var glXGetProcAddress func(name string) uintptr
|
||||
|
||||
func getProcAddressGL(name string) (uintptr, error) {
|
||||
if glXGetProcAddress == nil {
|
||||
if _, err := purego.Dlsym(libGL, "glXGetProcAddress"); err == nil {
|
||||
purego.RegisterLibFunc(&glXGetProcAddress, libGL, "glXGetProcAddress")
|
||||
} else if _, err := purego.Dlsym(libGL, "glXGetProcAddressARB"); err == nil {
|
||||
purego.RegisterLibFunc(&glXGetProcAddress, libGL, "glXGetProcAddressARB")
|
||||
}
|
||||
}
|
||||
if glXGetProcAddress == nil {
|
||||
return 0, fmt.Errorf("gl: failed to find glXGetProcAddress or glXGetProcAddressARB in libGL.so")
|
||||
}
|
||||
|
||||
return glXGetProcAddress(name), nil
|
||||
}
|
||||
|
||||
func getProcAddressGLES(name string) uintptr {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return uintptr(C.getProcAddressGLES(libGLES, cname))
|
||||
func getProcAddressGLES(name string) (uintptr, error) {
|
||||
proc, err := purego.Dlsym(libGLES, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return proc, nil
|
||||
}
|
||||
|
||||
Generated
Vendored
+2
@@ -21,6 +21,8 @@ package gl
|
||||
// #include <stdlib.h>
|
||||
// #include <EGL/egl.h>
|
||||
//
|
||||
// #cgo noescape getProcAddress
|
||||
// #cgo nocallback getProcAddress
|
||||
// static void* getProcAddress(const char* name) {
|
||||
// return eglGetProcAddress(name);
|
||||
// }
|
||||
|
||||
Generated
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall/js"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func copyUint8SliceToTemporaryArrayBuffer(src []uint8) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
js.CopyBytesToJS(tmpUint8Array, src)
|
||||
}
|
||||
|
||||
type numeric interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
||||
}
|
||||
|
||||
func copySliceToTemporaryArrayBuffer[T numeric](src []T) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
js.CopyBytesToJS(tmpUint8Array, unsafe.Slice((*byte)(unsafe.Pointer(&src[0])), len(src)*int(unsafe.Sizeof(T(0)))))
|
||||
runtime.KeepAlive(src)
|
||||
}
|
||||
Generated
Vendored
+8
-8
@@ -198,7 +198,7 @@ func (g *Graphics) uniformVariableName(idx int) string {
|
||||
return name
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("opengl: shader ID is invalid")
|
||||
}
|
||||
@@ -224,7 +224,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
|
||||
var idx int
|
||||
for i, typ := range shader.ir.Uniforms {
|
||||
n := typ.Uint32Count()
|
||||
n := typ.DwordCount()
|
||||
g.uniformVars[i].name = g.uniformVariableName(i)
|
||||
g.uniformVars[i].value = uniforms[idx : idx+n]
|
||||
g.uniformVars[i].typ = typ
|
||||
@@ -241,7 +241,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
g.uniformVars[idx].value[13] ^= 1 << 31
|
||||
}
|
||||
|
||||
var imgs [graphics.ShaderImageCount]textureVariable
|
||||
var imgs [graphics.ShaderSrcImageCount]textureVariable
|
||||
for i, srcID := range srcIDs {
|
||||
if srcID == graphicsdriver.InvalidImageID {
|
||||
continue
|
||||
@@ -259,7 +259,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
}
|
||||
g.uniformVars = g.uniformVars[:0]
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
if err := destination.ensureStencilBuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -274,14 +274,14 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
int32(dstRegion.Region.Dy()),
|
||||
)
|
||||
switch fillRule {
|
||||
case graphicsdriver.NonZero:
|
||||
case graphicsdriver.FillRuleNonZero:
|
||||
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||
g.context.ctx.StencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP)
|
||||
g.context.ctx.StencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP)
|
||||
g.context.ctx.ColorMask(false, false, false, false)
|
||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
case graphicsdriver.EvenOdd:
|
||||
case graphicsdriver.FillRuleEvenOdd:
|
||||
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||
g.context.ctx.StencilOpSeparate(gl.FRONT_AND_BACK, gl.KEEP, gl.KEEP, gl.INVERT)
|
||||
@@ -289,7 +289,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
|
||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
}
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
g.context.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
||||
g.context.ctx.StencilOpSeparate(gl.FRONT_AND_BACK, gl.KEEP, gl.KEEP, gl.KEEP)
|
||||
g.context.ctx.ColorMask(true, true, true, true)
|
||||
@@ -298,7 +298,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if fillRule != graphicsdriver.FillRuleFillAll {
|
||||
g.context.ctx.Disable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build ebitenginegldebug
|
||||
//go:build !playstation5 && ebitenginegldebug
|
||||
|
||||
package opengl
|
||||
|
||||
|
||||
Generated
Vendored
+8
-1
@@ -27,7 +27,7 @@ type graphicsPlatform struct {
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics(canvas js.Value) (graphicsdriver.Graphics, error) {
|
||||
func NewGraphics(canvas js.Value, colorSpace graphicsdriver.ColorSpace) (graphicsdriver.Graphics, error) {
|
||||
var glContext js.Value
|
||||
|
||||
attr := js.Global().Get("Object").New()
|
||||
@@ -41,6 +41,13 @@ func NewGraphics(canvas js.Value) (graphicsdriver.Graphics, error) {
|
||||
return nil, fmt.Errorf("opengl: getContext for webgl2 failed")
|
||||
}
|
||||
|
||||
switch colorSpace {
|
||||
case graphicsdriver.ColorSpaceSRGB:
|
||||
glContext.Set("drawingBufferColorSpace", "srgb")
|
||||
case graphicsdriver.ColorSpaceDisplayP3:
|
||||
glContext.Set("drawingBufferColorSpace", "display-p3")
|
||||
}
|
||||
|
||||
ctx, err := gl.NewDefaultContext(glContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+53
-21
@@ -12,20 +12,61 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !android && !ios && !js && !nintendosdk && !playstation5
|
||||
//go:build (freebsd || linux || netbsd || openbsd) && !android && !nintendosdk && !playstation5
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
|
||||
)
|
||||
|
||||
func isGLXExtensionForGL2Available() bool {
|
||||
var buf bytes.Buffer
|
||||
cmd := exec.Command("glxinfo")
|
||||
cmd.Stdout = &buf
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
const (
|
||||
indent = " "
|
||||
ext = "GLX_EXT_create_context_es2_profile"
|
||||
)
|
||||
|
||||
var listingExtensions bool
|
||||
s := bufio.NewScanner(&buf)
|
||||
for s.Scan() {
|
||||
line := s.Text()
|
||||
if !listingExtensions {
|
||||
if line == "GLX extensions:" {
|
||||
listingExtensions = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(line, indent) {
|
||||
listingExtensions = false
|
||||
break
|
||||
}
|
||||
|
||||
for len(line) > 0 {
|
||||
head, tail, _ := strings.Cut(line, ",")
|
||||
if strings.TrimSpace(head) == ext {
|
||||
return true
|
||||
}
|
||||
line = tail
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type graphicsPlatform struct {
|
||||
window *glfw.Window
|
||||
}
|
||||
@@ -33,10 +74,6 @@ type graphicsPlatform struct {
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
if microsoftgdk.IsXbox() {
|
||||
return nil, fmt.Errorf("opengl: OpenGL is not supported on Xbox")
|
||||
}
|
||||
|
||||
ctx, err := gl.NewDefaultContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -60,8 +97,12 @@ func setGLFWClientAPI(isES bool) error {
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMinor, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextCreationAPI, glfw.EGLContextAPI); err != nil {
|
||||
return err
|
||||
// Use GLX if the extension allows, or use EGL otherwise.
|
||||
// Prefer GLX since EGL might not work well on Wayland (#3152).
|
||||
if !isGLXExtensionForGL2Available() {
|
||||
if err := glfw.WindowHint(glfw.ContextCreationAPI, glfw.EGLContextAPI); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -75,15 +116,6 @@ func setGLFWClientAPI(isES bool) error {
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMinor, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
// macOS requires forward-compatible and a core profile.
|
||||
if runtime.GOOS == "darwin" {
|
||||
if err := glfw.WindowHint(glfw.OpenGLForwardCompat, glfw.True); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -103,11 +135,11 @@ func (g *Graphics) swapBuffers() error {
|
||||
// This needs to be called at least after SetMonitor.
|
||||
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
|
||||
if g.vsync {
|
||||
if err := glfw.SwapInterval(1); err != nil {
|
||||
if err := g.window.SwapInterval(1); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := glfw.SwapInterval(0); err != nil {
|
||||
if err := g.window.SwapInterval(0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
// Copyright 2024 The Ebitengine Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build darwin && !ios
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
)
|
||||
|
||||
type graphicsPlatform struct {
|
||||
window *glfw.Window
|
||||
}
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
ctx, err := gl.NewDefaultContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLAPI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMajor, 3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMinor, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// macOS requires forward-compatible and a core profile.
|
||||
if err := glfw.WindowHint(glfw.OpenGLForwardCompat, glfw.True); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newGraphics(ctx), nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetGLFWWindow(window *glfw.Window) {
|
||||
g.window = window
|
||||
}
|
||||
|
||||
func (g *Graphics) makeContextCurrent() error {
|
||||
return g.window.MakeContextCurrent()
|
||||
}
|
||||
|
||||
func (g *Graphics) swapBuffers() error {
|
||||
// Call SwapIntervals even though vsync is not changed.
|
||||
// When toggling to fullscreen, vsync state might be reset unexpectedly (#1787).
|
||||
|
||||
// SwapInterval is affected by the current monitor of the window.
|
||||
// This needs to be called at least after SetMonitor.
|
||||
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
|
||||
if g.vsync {
|
||||
if err := g.window.SwapInterval(1); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := g.window.SwapInterval(0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.window.SwapBuffers(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !ebitenginegldebug
|
||||
//go:build !playstation5 && !ebitenginegldebug
|
||||
|
||||
package opengl
|
||||
|
||||
|
||||
Generated
Vendored
+84
@@ -0,0 +1,84 @@
|
||||
// Copyright 2024 The Ebitengine Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
|
||||
)
|
||||
|
||||
type graphicsPlatform struct {
|
||||
window *glfw.Window
|
||||
}
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
if microsoftgdk.IsXbox() {
|
||||
return nil, fmt.Errorf("opengl: OpenGL is not supported on Xbox")
|
||||
}
|
||||
|
||||
ctx, err := gl.NewDefaultContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLAPI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMajor, 3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMinor, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newGraphics(ctx), nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetGLFWWindow(window *glfw.Window) {
|
||||
g.window = window
|
||||
}
|
||||
|
||||
func (g *Graphics) makeContextCurrent() error {
|
||||
return g.window.MakeContextCurrent()
|
||||
}
|
||||
|
||||
func (g *Graphics) swapBuffers() error {
|
||||
// Call SwapIntervals even though vsync is not changed.
|
||||
// When toggling to fullscreen, vsync state might be reset unexpectedly (#1787).
|
||||
|
||||
// SwapInterval is affected by the current monitor of the window.
|
||||
// This needs to be called at least after SetMonitor.
|
||||
// Without SwapInterval after SetMonitor, vsynch doesn't work (#375).
|
||||
if g.vsync {
|
||||
if err := g.window.SwapInterval(1); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := g.window.SwapInterval(0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.window.SwapBuffers(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+7
-7
@@ -37,10 +37,9 @@ type Image struct {
|
||||
|
||||
// framebuffer is a wrapper of OpenGL's framebuffer.
|
||||
type framebuffer struct {
|
||||
graphics *Graphics
|
||||
native framebufferNative
|
||||
width int
|
||||
height int
|
||||
native framebufferNative
|
||||
viewportWidth int
|
||||
viewportHeight int
|
||||
}
|
||||
|
||||
func (i *Image) ID() graphicsdriver.ImageID {
|
||||
@@ -81,7 +80,7 @@ func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) framebufferSize() (int, int) {
|
||||
func (i *Image) viewportSize() (int, int) {
|
||||
if i.screen {
|
||||
// The (default) framebuffer size can't be converted to a power of 2.
|
||||
// On browsers, i.width and i.height are used as viewport size and
|
||||
@@ -96,11 +95,12 @@ func (i *Image) ensureFramebuffer() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
w, h := i.framebufferSize()
|
||||
w, h := i.viewportSize()
|
||||
if i.screen {
|
||||
i.framebuffer = i.graphics.context.newScreenFramebuffer(w, h)
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := i.graphics.context.newFramebuffer(i.texture, w, h)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -118,7 +118,7 @@ func (i *Image) ensureStencilBuffer() error {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := i.graphics.context.newRenderbuffer(i.framebufferSize())
|
||||
r, err := i.graphics.context.newRenderbuffer(i.viewportSize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Generated
Vendored
+43
-27
@@ -53,28 +53,33 @@ func (a *arrayBufferLayout) names() []string {
|
||||
return ns
|
||||
}
|
||||
|
||||
// totalBytes returns the size in bytes for one element of the array buffer.
|
||||
func (a *arrayBufferLayout) totalBytes() int {
|
||||
// float32Count returns the total float32 count for one element of the array buffer.
|
||||
func (a *arrayBufferLayout) float32Count() int {
|
||||
if a.total != 0 {
|
||||
return a.total
|
||||
}
|
||||
t := 0
|
||||
for _, p := range a.parts {
|
||||
t += floatSizeInBytes * p.num
|
||||
t += p.num
|
||||
}
|
||||
a.total = t
|
||||
return a.total
|
||||
}
|
||||
|
||||
func (a *arrayBufferLayout) addPart(part arrayBufferLayoutPart) {
|
||||
a.parts = append(a.parts, part)
|
||||
a.total = 0
|
||||
}
|
||||
|
||||
// enable starts using the array buffer.
|
||||
func (a *arrayBufferLayout) enable(context *context) {
|
||||
for i := range a.parts {
|
||||
context.ctx.EnableVertexAttribArray(uint32(i))
|
||||
}
|
||||
total := a.totalBytes()
|
||||
total := a.float32Count()
|
||||
offset := 0
|
||||
for i, p := range a.parts {
|
||||
context.ctx.VertexAttribPointer(uint32(i), int32(p.num), gl.FLOAT, false, int32(total), offset)
|
||||
context.ctx.VertexAttribPointer(uint32(i), int32(p.num), gl.FLOAT, false, int32(floatSizeInBytes*total), offset)
|
||||
offset += floatSizeInBytes * p.num
|
||||
}
|
||||
}
|
||||
@@ -88,28 +93,39 @@ func (a *arrayBufferLayout) disable(context *context) {
|
||||
}
|
||||
|
||||
// theArrayBufferLayout is the array buffer layout for Ebitengine.
|
||||
var theArrayBufferLayout = arrayBufferLayout{
|
||||
// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
|
||||
parts: []arrayBufferLayoutPart{
|
||||
{
|
||||
name: "A0",
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "A1",
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "A2",
|
||||
num: 4,
|
||||
},
|
||||
},
|
||||
}
|
||||
var theArrayBufferLayout arrayBufferLayout
|
||||
|
||||
func init() {
|
||||
vertexFloatCount := theArrayBufferLayout.totalBytes() / floatSizeInBytes
|
||||
if graphics.VertexFloatCount != vertexFloatCount {
|
||||
panic(fmt.Sprintf("vertex float num must be %d but %d", graphics.VertexFloatCount, vertexFloatCount))
|
||||
theArrayBufferLayout = arrayBufferLayout{
|
||||
// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
|
||||
parts: []arrayBufferLayoutPart{
|
||||
{
|
||||
name: "A0",
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "A1",
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "A2",
|
||||
num: 4,
|
||||
},
|
||||
},
|
||||
}
|
||||
n := theArrayBufferLayout.float32Count()
|
||||
diff := graphics.VertexFloatCount - n
|
||||
if diff == 0 {
|
||||
return
|
||||
}
|
||||
if diff%4 != 0 {
|
||||
panic("opengl: unexpected attribute layout")
|
||||
}
|
||||
for i := 0; i < diff/4; i++ {
|
||||
theArrayBufferLayout.addPart(arrayBufferLayoutPart{
|
||||
name: fmt.Sprintf("A%d", i+3),
|
||||
num: 4,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +275,7 @@ func (g *Graphics) textureVariableName(idx int) string {
|
||||
}
|
||||
|
||||
// useProgram uses the program (programTexture).
|
||||
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderImageCount]textureVariable) error {
|
||||
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderSrcImageCount]textureVariable) error {
|
||||
if g.state.lastProgram != program {
|
||||
g.context.ctx.UseProgram(uint32(program))
|
||||
|
||||
@@ -276,7 +292,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
|
||||
if u.value == nil {
|
||||
continue
|
||||
}
|
||||
if got, expected := len(u.value), u.typ.Uint32Count(); got != expected {
|
||||
if got, expected := len(u.value), u.typ.DwordCount(); got != expected {
|
||||
// Copy a shaderir.Type value once. Do not pass u.typ directly to fmt.Errorf arguments, or
|
||||
// the value u would be allocated on heap.
|
||||
typ := u.typ
|
||||
|
||||
+23
-2
@@ -18,6 +18,7 @@ package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
@@ -59,13 +60,13 @@ func (s *Shader) compile() error {
|
||||
|
||||
vs, err := s.graphics.context.newShader(gl.VERTEX_SHADER, vssrc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opengl: vertex shader compile error: %v, source:\n%s", err, vssrc)
|
||||
return err
|
||||
}
|
||||
defer s.graphics.context.ctx.DeleteShader(uint32(vs))
|
||||
|
||||
fs, err := s.graphics.context.newShader(gl.FRAGMENT_SHADER, fssrc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opengl: fragment shader compile error: %v, source:\n%s", err, fssrc)
|
||||
return err
|
||||
}
|
||||
defer s.graphics.context.ctx.DeleteShader(uint32(fs))
|
||||
|
||||
@@ -74,6 +75,26 @@ func (s *Shader) compile() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the shader compile status asynchronously if possible.
|
||||
// The function 'compile' itself is still blocking, but at least this gives a chance to other goroutines to run
|
||||
// while waiting for the shader compilation.
|
||||
if s.graphics.context.hasParallelShaderCompile() {
|
||||
for s.graphics.context.ctx.GetShaderi(uint32(vs), gl.COMPLETION_STATUS_KHR) != gl.TRUE ||
|
||||
s.graphics.context.ctx.GetShaderi(uint32(fs), gl.COMPLETION_STATUS_KHR) != gl.TRUE {
|
||||
runtime.Gosched()
|
||||
}
|
||||
}
|
||||
|
||||
// Check errors only after linking fails.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#dont_check_shader_compile_status_unless_linking_fails
|
||||
if s.graphics.context.ctx.GetProgrami(uint32(p), gl.LINK_STATUS) == gl.FALSE {
|
||||
programInfo := s.graphics.context.ctx.GetProgramInfoLog(uint32(p))
|
||||
vertexShaderInfo := s.graphics.context.ctx.GetShaderInfoLog(uint32(vs))
|
||||
fragmentShaderInfo := s.graphics.context.ctx.GetShaderInfoLog(uint32(fs))
|
||||
return fmt.Errorf("opengl: program error: %s\nvertex shader error: %s\nvertex shader source: %s\nfragment shader error: %s\nfragment shader source: %s",
|
||||
programInfo, vertexShaderInfo, vssrc, fragmentShaderInfo, fssrc)
|
||||
}
|
||||
|
||||
s.p = p
|
||||
return nil
|
||||
}
|
||||
|
||||
Generated
Vendored
+38
-8
@@ -14,28 +14,58 @@
|
||||
|
||||
//go:build playstation5
|
||||
|
||||
// The actual implementation will be provided by -overlay.
|
||||
// The actual implementation will be provided by github.com/hajimehoshi/uwagaki.
|
||||
|
||||
#include "graphics_playstation5.h"
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_InitializeGraphics(void) {
|
||||
extern "C" ebitengine_Error ebitengine_InitializeGraphics(void) { return {}; }
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_NewImage(int *image, int width,
|
||||
int height) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_NewImage(int* image, int width, int height) {
|
||||
extern "C" void ebitengine_ReadPixels(int image, uint8_t *pixels,
|
||||
ebitengine_Region region) {}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_FlushReadPixels(int image) { return {}; }
|
||||
|
||||
extern "C" void ebitengine_WritePixels(int image, const uint8_t *pixels,
|
||||
ebitengine_Region region) {}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_FlushWritePixels(int image) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_NewScreenFramebufferImage(int* image, int width, int height) {
|
||||
extern "C" ebitengine_Error
|
||||
ebitengine_NewScreenFramebufferImage(int *image, int width, int height) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" void ebitengine_DisposeImage(int id) {
|
||||
}
|
||||
extern "C" void ebitengine_DisposeImage(int id) {}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_NewShader(int* shader, const char* source) {
|
||||
extern "C" void ebitengine_Begin() {}
|
||||
|
||||
extern "C" void ebitengine_End(int present) {}
|
||||
|
||||
extern "C" void ebitengine_SetVertices(const float *vertices, int vertex_count,
|
||||
const uint32_t *indices,
|
||||
int index_count) {}
|
||||
|
||||
extern "C" ebitengine_Error
|
||||
ebitengine_DrawTriangles(int dst, const int *srcs, int src_count, int shader,
|
||||
const ebitengine_DstRegion *dst_regions,
|
||||
int dst_region_count, int index_offset,
|
||||
ebitengine_Blend blend, const uint32_t *uniforms,
|
||||
int uniform_count, int fill_rule) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" void ebitengine_DisposeShader(int id) {
|
||||
extern "C" ebitengine_Error ebitengine_NewShader(
|
||||
int *shader, const char *vertex_header, int vertex_header_size,
|
||||
const char *vertex_text, int vertex_text_size, const char *pixel_header,
|
||||
int pixel_header_size, const char *pixel_text, int pixel_text_size) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" void ebitengine_DisposeShader(int id) {}
|
||||
|
||||
Generated
Vendored
+89
-6
@@ -17,16 +17,24 @@
|
||||
package playstation5
|
||||
|
||||
// #include "graphics_playstation5.h"
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
//export ebitengine_ProjectionMatrixUniformDwordIndex
|
||||
func ebitengine_ProjectionMatrixUniformDwordIndex() C.int {
|
||||
return C.int(graphics.ProjectionMatrixUniformDwordIndex)
|
||||
}
|
||||
|
||||
type playstation5Error struct {
|
||||
name string
|
||||
code int
|
||||
@@ -60,10 +68,16 @@ func (g *Graphics) Initialize() error {
|
||||
}
|
||||
|
||||
func (g *Graphics) Begin() error {
|
||||
C.ebitengine_Begin()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) End(present bool) error {
|
||||
var cPresent C.int
|
||||
if present {
|
||||
cPresent = 1
|
||||
}
|
||||
C.ebitengine_End(cPresent)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,11 +85,16 @@ func (g *Graphics) SetTransparent(transparent bool) {
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVertices(vertices []float32, indices []uint32) error {
|
||||
defer runtime.KeepAlive(vertices)
|
||||
defer runtime.KeepAlive(indices)
|
||||
C.ebitengine_SetVertices((*C.float)(unsafe.SliceData(vertices)), C.int(len(vertices)), (*C.uint32_t)(unsafe.SliceData(indices)), C.int(len(indices)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
var id C.int
|
||||
width = graphics.InternalImageSize(width)
|
||||
height = graphics.InternalImageSize(height)
|
||||
if err := C.ebitengine_NewImage(&id, C.int(width), C.int(height)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return nil, newPlaystation5Error("(*playstation5.Graphics).NewImage", err)
|
||||
}
|
||||
@@ -98,7 +117,7 @@ func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
||||
}
|
||||
|
||||
func (g *Graphics) NeedsClearingScreen() bool {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *Graphics) MaxImageSize() int {
|
||||
@@ -106,9 +125,15 @@ func (g *Graphics) MaxImageSize() int {
|
||||
}
|
||||
|
||||
func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
s := precompiledShaders[program.SourceHash]
|
||||
defer runtime.KeepAlive(s)
|
||||
|
||||
var id C.int
|
||||
// TODO: Give a source code.
|
||||
if err := C.ebitengine_NewShader(&id, nil); !C.ebitengine_IsErrorNil(&err) {
|
||||
if err := C.ebitengine_NewShader(&id,
|
||||
(*C.char)(unsafe.Pointer(unsafe.SliceData(s.vertexHeader))), C.int(len(s.vertexHeader)),
|
||||
(*C.char)(unsafe.Pointer(unsafe.SliceData(s.vertexText))), C.int(len(s.vertexText)),
|
||||
(*C.char)(unsafe.Pointer(unsafe.SliceData(s.pixelHeader))), C.int(len(s.pixelHeader)),
|
||||
(*C.char)(unsafe.Pointer(unsafe.SliceData(s.pixelText))), C.int(len(s.pixelText))); !C.ebitengine_IsErrorNil(&err) {
|
||||
return nil, newPlaystation5Error("(*playstation5.Graphics).NewShader", err)
|
||||
}
|
||||
return &Shader{
|
||||
@@ -116,7 +141,43 @@ func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dst graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, shader graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
func (g *Graphics) DrawTriangles(dst graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shader graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||
cSrcs := make([]C.int, len(srcs))
|
||||
for i, src := range srcs {
|
||||
cSrcs[i] = C.int(src)
|
||||
}
|
||||
defer runtime.KeepAlive(cSrcs)
|
||||
|
||||
cDstRegions := make([]C.ebitengine_DstRegion, len(dstRegions))
|
||||
defer runtime.KeepAlive(cDstRegions)
|
||||
for i, r := range dstRegions {
|
||||
cDstRegions[i] = C.ebitengine_DstRegion{
|
||||
min_x: C.int(r.Region.Min.X),
|
||||
min_y: C.int(r.Region.Min.Y),
|
||||
max_x: C.int(r.Region.Max.X),
|
||||
max_y: C.int(r.Region.Max.Y),
|
||||
index_count: C.int(r.IndexCount),
|
||||
}
|
||||
}
|
||||
|
||||
cBlend := C.ebitengine_Blend{
|
||||
factor_src_rgb: C.uint8_t(blend.BlendFactorSourceRGB),
|
||||
factor_src_alpha: C.uint8_t(blend.BlendFactorSourceAlpha),
|
||||
factor_dst_rgb: C.uint8_t(blend.BlendFactorDestinationRGB),
|
||||
factor_dst_alpha: C.uint8_t(blend.BlendFactorDestinationAlpha),
|
||||
operation_rgb: C.uint8_t(blend.BlendOperationRGB),
|
||||
operation_alpha: C.uint8_t(blend.BlendOperationAlpha),
|
||||
}
|
||||
|
||||
cUniforms := make([]C.uint32_t, len(uniforms))
|
||||
defer runtime.KeepAlive(cUniforms)
|
||||
for i, u := range uniforms {
|
||||
cUniforms[i] = C.uint32_t(u)
|
||||
}
|
||||
|
||||
if err := C.ebitengine_DrawTriangles(C.int(dst), unsafe.SliceData(cSrcs), C.int(len(cSrcs)), C.int(shader), unsafe.SliceData(cDstRegions), C.int(len(cDstRegions)), C.int(indexOffset), cBlend, unsafe.SliceData(cUniforms), C.int(len(cUniforms)), C.int(fillRule)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return newPlaystation5Error("(*playstation5.Graphics).DrawTriangles", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -133,12 +194,34 @@ func (i *Image) Dispose() {
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
// TODO: Implement this
|
||||
for _, a := range args {
|
||||
region := C.ebitengine_Region{
|
||||
min_x: C.int(a.Region.Min.X),
|
||||
min_y: C.int(a.Region.Min.Y),
|
||||
max_x: C.int(a.Region.Max.X),
|
||||
max_y: C.int(a.Region.Max.Y),
|
||||
}
|
||||
C.ebitengine_ReadPixels(C.int(i.id), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(a.Pixels))), region)
|
||||
}
|
||||
if err := C.ebitengine_FlushReadPixels(C.int(i.id)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return newPlaystation5Error("(*playstation5.Image).ReadPixels", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
// TODO: Implement this
|
||||
for _, a := range args {
|
||||
region := C.ebitengine_Region{
|
||||
min_x: C.int(a.Region.Min.X),
|
||||
min_y: C.int(a.Region.Min.Y),
|
||||
max_x: C.int(a.Region.Max.X),
|
||||
max_y: C.int(a.Region.Max.Y),
|
||||
}
|
||||
C.ebitengine_WritePixels(C.int(i.id), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(a.Pixels))), region)
|
||||
}
|
||||
if err := C.ebitengine_FlushWritePixels(C.int(i.id)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return newPlaystation5Error("(*playstation5.Image).WritePixels", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
vendor/github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/playstation5/graphics_playstation5.h
Generated
Vendored
+80
-6
@@ -19,26 +19,100 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ebitengine_ProjectionMatrixUniformDwordIndex();
|
||||
|
||||
typedef struct ebitengine_Error {
|
||||
const char* message;
|
||||
int code;
|
||||
const char *message;
|
||||
int code;
|
||||
} ebitengine_Error;
|
||||
|
||||
static bool ebitengine_IsErrorNil(ebitengine_Error* err) {
|
||||
static bool ebitengine_IsErrorNil(ebitengine_Error *err) {
|
||||
return err->message == NULL && err->code == 0;
|
||||
}
|
||||
|
||||
typedef struct ebitengine_Region {
|
||||
int min_x;
|
||||
int min_y;
|
||||
int max_x;
|
||||
int max_y;
|
||||
} ebitengine_Region;
|
||||
|
||||
typedef struct ebitengine_DstRegion {
|
||||
int min_x;
|
||||
int min_y;
|
||||
int max_x;
|
||||
int max_y;
|
||||
int index_count;
|
||||
} ebitengine_DstRegion;
|
||||
|
||||
// kBlendFactor* and kBlendOperation* must be synced with
|
||||
// internal/graphicsdriver/blend.go.
|
||||
|
||||
enum {
|
||||
kBlendFactorZero = 0,
|
||||
kBlendFactorOne = 1,
|
||||
kBlendFactorSourceColor = 2,
|
||||
kBlendFactorOneMinusSourceColor = 3,
|
||||
kBlendFactorSourceAlpha = 4,
|
||||
kBlendFactorOneMinusSourceAlpha = 5,
|
||||
kBlendFactorDestinationColor = 6,
|
||||
kBlendFactorOneMinusDestinationColor = 7,
|
||||
kBlendFactorDestinationAlpha = 8,
|
||||
kBlendFactorOneMinusDestinationAlpha = 9,
|
||||
kBlendFactorSourceAlphaSaturated = 10,
|
||||
};
|
||||
|
||||
enum {
|
||||
kBlendOperationAdd = 0,
|
||||
kBlendOperationSubtract = 1,
|
||||
kBlendOperationReverseSubtract = 2,
|
||||
kBlendOperationMin = 3,
|
||||
kBlendOperationMax = 4,
|
||||
};
|
||||
|
||||
typedef struct ebitengine_Blend {
|
||||
uint8_t factor_src_rgb;
|
||||
uint8_t factor_src_alpha;
|
||||
uint8_t factor_dst_rgb;
|
||||
uint8_t factor_dst_alpha;
|
||||
uint8_t operation_rgb;
|
||||
uint8_t operation_alpha;
|
||||
} ebitengine_Blend;
|
||||
|
||||
ebitengine_Error ebitengine_InitializeGraphics(void);
|
||||
ebitengine_Error ebitengine_NewImage(int* image, int width, int height);
|
||||
ebitengine_Error ebitengine_NewScreenFramebufferImage(int* image, int width, int height);
|
||||
ebitengine_Error ebitengine_NewImage(int *image, int width, int height);
|
||||
ebitengine_Error ebitengine_NewScreenFramebufferImage(int *image, int width,
|
||||
int height);
|
||||
void ebitengine_ReadPixels(int image, uint8_t *pixels,
|
||||
ebitengine_Region region);
|
||||
ebitengine_Error ebitengine_FlushReadPixels(int image);
|
||||
void ebitengine_WritePixels(int image, const uint8_t *pixels,
|
||||
ebitengine_Region region);
|
||||
ebitengine_Error ebitengine_FlushWritePixels(int image);
|
||||
void ebitengine_DisposeImage(int id);
|
||||
|
||||
ebitengine_Error ebitengine_NewShader(int* shader, const char* source);
|
||||
void ebitengine_Begin();
|
||||
void ebitengine_End(int present);
|
||||
void ebitengine_SetVertices(const float *vertices, int vertex_count,
|
||||
const uint32_t *indices, int index_count);
|
||||
|
||||
ebitengine_Error
|
||||
ebitengine_DrawTriangles(int dst, const int *srcs, int src_count, int shader,
|
||||
const ebitengine_DstRegion *dst_regions,
|
||||
int dst_region_count, int indexOffset,
|
||||
ebitengine_Blend blend, const uint32_t *uniforms,
|
||||
int uniform_count, int fill_rule);
|
||||
|
||||
ebitengine_Error ebitengine_NewShader(
|
||||
int *shader, const char *vertex_header, int vertex_header_size,
|
||||
const char *vertex_text, int vertex_text_size, const char *pixel_header,
|
||||
int pixel_header_size, const char *pixel_text, int pixel_text_size);
|
||||
void ebitengine_DisposeShader(int id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright 2024 The Ebitengine Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build playstation5
|
||||
|
||||
package playstation5
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
var (
|
||||
// precompiledShaders is a map to store precompiled shaders.
|
||||
// precompiledShaders is initialized by a separate tool.
|
||||
precompiledShaders map[shaderir.SourceHash]*shaderSource
|
||||
)
|
||||
|
||||
type shaderSource struct {
|
||||
vertexHeader []byte
|
||||
vertexText []byte
|
||||
pixelHeader []byte
|
||||
pixelText []byte
|
||||
}
|
||||
Reference in New Issue
Block a user