vendor dependencies, make some changes to how input is done
This commit is contained in:
+77
@@ -0,0 +1,77 @@
|
||||
// Copyright 2022 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 graphicsdriver
|
||||
|
||||
type Blend struct {
|
||||
BlendFactorSourceRGB BlendFactor
|
||||
BlendFactorSourceAlpha BlendFactor
|
||||
BlendFactorDestinationRGB BlendFactor
|
||||
BlendFactorDestinationAlpha BlendFactor
|
||||
BlendOperationRGB BlendOperation
|
||||
BlendOperationAlpha BlendOperation
|
||||
}
|
||||
|
||||
type BlendFactor byte
|
||||
|
||||
const (
|
||||
BlendFactorZero BlendFactor = iota
|
||||
BlendFactorOne
|
||||
BlendFactorSourceColor
|
||||
BlendFactorOneMinusSourceColor
|
||||
BlendFactorSourceAlpha
|
||||
BlendFactorOneMinusSourceAlpha
|
||||
BlendFactorDestinationColor
|
||||
BlendFactorOneMinusDestinationColor
|
||||
BlendFactorDestinationAlpha
|
||||
BlendFactorOneMinusDestinationAlpha
|
||||
BlendFactorSourceAlphaSaturated
|
||||
)
|
||||
|
||||
type BlendOperation byte
|
||||
|
||||
const (
|
||||
BlendOperationAdd BlendOperation = iota
|
||||
BlendOperationSubtract
|
||||
BlendOperationReverseSubtract
|
||||
BlendOperationMin
|
||||
BlendOperationMax
|
||||
)
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
var BlendCopy = Blend{
|
||||
BlendFactorSourceRGB: BlendFactorOne,
|
||||
BlendFactorSourceAlpha: BlendFactorOne,
|
||||
BlendFactorDestinationRGB: BlendFactorZero,
|
||||
BlendFactorDestinationAlpha: BlendFactorZero,
|
||||
BlendOperationRGB: BlendOperationAdd,
|
||||
BlendOperationAlpha: BlendOperationAdd,
|
||||
}
|
||||
Generated
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build 386 || arm
|
||||
|
||||
package directx
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type _D3D12_DEPTH_STENCIL_VIEW_DESC struct {
|
||||
Format _DXGI_FORMAT
|
||||
ViewDimension _D3D12_DSV_DIMENSION
|
||||
Flags _D3D12_DSV_FLAGS
|
||||
Texture2D _D3D12_TEX2D_DSV // Union
|
||||
_ [12 - unsafe.Sizeof(_D3D12_TEX2D_DSV{})]byte // Padding for union
|
||||
}
|
||||
|
||||
type _D3D12_RESOURCE_DESC struct {
|
||||
Dimension _D3D12_RESOURCE_DIMENSION
|
||||
_ [4]byte // Padding
|
||||
Alignment uint64
|
||||
Width uint64
|
||||
Height uint32
|
||||
DepthOrArraySize uint16
|
||||
MipLevels uint16
|
||||
Format _DXGI_FORMAT
|
||||
SampleDesc _DXGI_SAMPLE_DESC
|
||||
Layout _D3D12_TEXTURE_LAYOUT
|
||||
Flags _D3D12_RESOURCE_FLAGS
|
||||
|
||||
// This is a pseudo padding which D3D12_RESOURCE_DESC1 would use.
|
||||
// Mysteriously, some functions don't work correctly without this hack (#2867).
|
||||
_ [12]byte
|
||||
}
|
||||
|
||||
type _D3D12_ROOT_PARAMETER struct {
|
||||
ParameterType _D3D12_ROOT_PARAMETER_TYPE
|
||||
DescriptorTable _D3D12_ROOT_DESCRIPTOR_TABLE // Union
|
||||
_ [4]byte // Padding
|
||||
ShaderVisibility _D3D12_SHADER_VISIBILITY
|
||||
}
|
||||
Generated
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package directx
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type _D3D12_DEPTH_STENCIL_VIEW_DESC struct {
|
||||
Format _DXGI_FORMAT
|
||||
ViewDimension _D3D12_DSV_DIMENSION
|
||||
Flags _D3D12_DSV_FLAGS
|
||||
_ [4]byte // Padding
|
||||
Texture2D _D3D12_TEX2D_DSV // Union
|
||||
_ [12 - unsafe.Sizeof(_D3D12_TEX2D_DSV{})]byte // Padding for union
|
||||
}
|
||||
|
||||
type _D3D12_RESOURCE_DESC struct {
|
||||
Dimension _D3D12_RESOURCE_DIMENSION
|
||||
Alignment uint64
|
||||
Width uint64
|
||||
Height uint32
|
||||
DepthOrArraySize uint16
|
||||
MipLevels uint16
|
||||
Format _DXGI_FORMAT
|
||||
SampleDesc _DXGI_SAMPLE_DESC
|
||||
Layout _D3D12_TEXTURE_LAYOUT
|
||||
Flags _D3D12_RESOURCE_FLAGS
|
||||
}
|
||||
|
||||
type _D3D12_ROOT_PARAMETER struct {
|
||||
ParameterType _D3D12_ROOT_PARAMETER_TYPE
|
||||
DescriptorTable _D3D12_ROOT_DESCRIPTOR_TABLE // Union
|
||||
ShaderVisibility _D3D12_SHADER_VISIBILITY
|
||||
}
|
||||
Generated
Vendored
+228
@@ -0,0 +1,228 @@
|
||||
// Copyright 2022 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 microsoftgdk
|
||||
|
||||
package directx
|
||||
|
||||
// Some functions of ID3D12GraphicsCommandList has additional logics besides the original COM function call.
|
||||
// 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));
|
||||
// }
|
||||
// }
|
||||
|
||||
// #include <stdint.h>
|
||||
//
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearDepthStencilView(void* i, uintptr_t depthStencilView, int32_t clearFlags, float depth, uint8_t stencil, uint32_t numRects, void* pRects);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ClearRenderTargetView(void* i, uintptr_t pRenderTargetView, void* colorRGBA, uint32_t numRects, void* pRects);
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Close(void* i);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_CopyTextureRegion(void* i, void* pDst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, void* pSrc, void* pSrcBox);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_DrawIndexedInstanced(void* i, uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetIndexBuffer(void* i, void* pView);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetPrimitiveTopology(void* i, int32_t primitiveTopology);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_IASetVertexBuffers(void* i, uint32_t startSlot, uint32_t numViews, void* pViews);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetRenderTargets(void* i, uint32_t numRenderTargetDescriptors, void* pRenderTargetDescriptors, int rtsSingleHandleToDescriptorRange, void* pDepthStencilDescriptor);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_OMSetStencilRef(void* i, uint32_t stencilRef);
|
||||
// uint32_t Ebitengine_ID3D12GraphicsCommandList_Release(void* i);
|
||||
// uintptr_t Ebitengine_ID3D12GraphicsCommandList_Reset(void* i, void* pAllocator, void* pInitialState);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_ResourceBarrier(void* i, uint32_t numBarriers, void* pBarriers);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetViewports(void* i, uint32_t numViewports, void* pViewports);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_RSSetScissorRects(void* i, uint32_t numRects, void* pRects);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetDescriptorHeaps(void* i, uint32_t numDescriptorHeaps, void* ppDescriptorHeaps);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(void* i, uint32_t rootParameterIndex, uint64_t baseDescriptorPtr);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootSignature(void* i, void* pRootSignature);
|
||||
// void Ebitengine_ID3D12GraphicsCommandList_SetPipelineState(void* i, void* pPipelineState);
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
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 {
|
||||
pRects = &rects[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_ClearDepthStencilView(unsafe.Pointer(i), C.uintptr_t(depthStencilView.ptr), C.int32_t(clearFlags), C.float(depth), C.uint8_t(stencil), C.uint32_t(len(rects)), unsafe.Pointer(pRects))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ClearRenderTargetView(i *_ID3D12GraphicsCommandList, pRenderTargetView _D3D12_CPU_DESCRIPTOR_HANDLE, colorRGBA [4]float32, rects []_D3D12_RECT) {
|
||||
var pRects *_D3D12_RECT
|
||||
if len(rects) > 0 {
|
||||
pRects = &rects[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_ClearRenderTargetView(unsafe.Pointer(i), C.uintptr_t(pRenderTargetView.ptr), unsafe.Pointer(&colorRGBA[0]), C.uint32_t(len(rects)), unsafe.Pointer(pRects))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Close(i *_ID3D12GraphicsCommandList) uintptr {
|
||||
r := C.Ebitengine_ID3D12GraphicsCommandList_Close(unsafe.Pointer(i))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_CopyTextureRegion(i *_ID3D12GraphicsCommandList, pDst unsafe.Pointer, dstX uint32, dstY uint32, dstZ uint32, pSrc unsafe.Pointer, pSrcBox *_D3D12_BOX) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_CopyTextureRegion(unsafe.Pointer(i), pDst, C.uint32_t(dstX), C.uint32_t(dstY), C.uint32_t(dstZ), pSrc, unsafe.Pointer(pSrcBox))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_DrawIndexedInstanced(i *_ID3D12GraphicsCommandList, indexCountPerInstance uint32, instanceCount uint32, startIndexLocation uint32, baseVertexLocation int32, startInstanceLocation uint32) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_DrawIndexedInstanced(unsafe.Pointer(i),
|
||||
C.uint32_t(indexCountPerInstance), C.uint32_t(instanceCount), C.uint32_t(startIndexLocation),
|
||||
C.int32_t(baseVertexLocation), C.uint32_t(startInstanceLocation))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetIndexBuffer(i *_ID3D12GraphicsCommandList, pView *_D3D12_INDEX_BUFFER_VIEW) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_IASetIndexBuffer(unsafe.Pointer(i), unsafe.Pointer(pView))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetPrimitiveTopology(i *_ID3D12GraphicsCommandList, primitiveTopology _D3D_PRIMITIVE_TOPOLOGY) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_IASetPrimitiveTopology(unsafe.Pointer(i), C.int32_t(primitiveTopology))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetVertexBuffers(i *_ID3D12GraphicsCommandList, startSlot uint32, views []_D3D12_VERTEX_BUFFER_VIEW) {
|
||||
var pViews *_D3D12_VERTEX_BUFFER_VIEW
|
||||
if len(views) > 0 {
|
||||
pViews = &views[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_IASetVertexBuffers(unsafe.Pointer(i), C.uint32_t(startSlot), C.uint32_t(len(views)), unsafe.Pointer(pViews))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_OMSetRenderTargets(i *_ID3D12GraphicsCommandList, renderTargetDescriptors []_D3D12_CPU_DESCRIPTOR_HANDLE, rtsSingleHandleToDescriptorRange bool, pDepthStencilDescriptor *_D3D12_CPU_DESCRIPTOR_HANDLE) {
|
||||
var pRenderTargetDescriptors *_D3D12_CPU_DESCRIPTOR_HANDLE
|
||||
if len(renderTargetDescriptors) > 0 {
|
||||
pRenderTargetDescriptors = &renderTargetDescriptors[0]
|
||||
}
|
||||
v := 0
|
||||
if rtsSingleHandleToDescriptorRange {
|
||||
v = 1
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_OMSetRenderTargets(unsafe.Pointer(i), C.uint32_t(len(renderTargetDescriptors)), unsafe.Pointer(pRenderTargetDescriptors), C.int(v), unsafe.Pointer(pDepthStencilDescriptor))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_OMSetStencilRef(i *_ID3D12GraphicsCommandList, stencilRef uint32) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_OMSetStencilRef(unsafe.Pointer(i), C.uint32_t(stencilRef))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Release(i *_ID3D12GraphicsCommandList) uint32 {
|
||||
return uint32(C.Ebitengine_ID3D12GraphicsCommandList_Release(unsafe.Pointer(i)))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Reset(i *_ID3D12GraphicsCommandList, pAllocator *_ID3D12CommandAllocator, pInitialState *_ID3D12PipelineState) uintptr {
|
||||
r := C.Ebitengine_ID3D12GraphicsCommandList_Reset(unsafe.Pointer(i), unsafe.Pointer(pAllocator), unsafe.Pointer(pInitialState))
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ResourceBarrier(i *_ID3D12GraphicsCommandList, barriers []_D3D12_RESOURCE_BARRIER_Transition) {
|
||||
var pBarriers *_D3D12_RESOURCE_BARRIER_Transition
|
||||
if len(barriers) > 0 {
|
||||
pBarriers = &barriers[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_ResourceBarrier(unsafe.Pointer(i), C.uint32_t(len(barriers)), unsafe.Pointer(pBarriers))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_RSSetViewports(i *_ID3D12GraphicsCommandList, viewports []_D3D12_VIEWPORT) {
|
||||
var pViewports *_D3D12_VIEWPORT
|
||||
if len(viewports) > 0 {
|
||||
pViewports = &viewports[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_RSSetViewports(unsafe.Pointer(i), C.uint32_t(len(viewports)), unsafe.Pointer(pViewports))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_RSSetScissorRects(i *_ID3D12GraphicsCommandList, rects []_D3D12_RECT) {
|
||||
var pRects *_D3D12_RECT
|
||||
if len(rects) > 0 {
|
||||
pRects = &rects[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_RSSetScissorRects(unsafe.Pointer(i), C.uint32_t(len(rects)), unsafe.Pointer(pRects))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetDescriptorHeaps(i *_ID3D12GraphicsCommandList, descriptorHeaps []*_ID3D12DescriptorHeap) {
|
||||
var ppDescriptorHeaps **_ID3D12DescriptorHeap
|
||||
if len(descriptorHeaps) > 0 {
|
||||
ppDescriptorHeaps = &descriptorHeaps[0]
|
||||
}
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_SetDescriptorHeaps(unsafe.Pointer(i), C.uint32_t(len(descriptorHeaps)), unsafe.Pointer(ppDescriptorHeaps))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(i *_ID3D12GraphicsCommandList, rootParameterIndex uint32, baseDescriptor _D3D12_GPU_DESCRIPTOR_HANDLE) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(unsafe.Pointer(i), C.uint32_t(rootParameterIndex), C.uint64_t(baseDescriptor.ptr))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetGraphicsRootSignature(i *_ID3D12GraphicsCommandList, pRootSignature *_ID3D12RootSignature) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_SetGraphicsRootSignature(unsafe.Pointer(i), unsafe.Pointer(pRootSignature))
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetPipelineState(i *_ID3D12GraphicsCommandList, pPipelineState *_ID3D12PipelineState) {
|
||||
C.Ebitengine_ID3D12GraphicsCommandList_SetPipelineState(unsafe.Pointer(i), unsafe.Pointer(pPipelineState))
|
||||
}
|
||||
Generated
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright 2022 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 !microsoftgdk
|
||||
|
||||
package directx
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func _ID3D12GraphicsCommandList_ClearDepthStencilView(i *_ID3D12GraphicsCommandList, depthStencilView _D3D12_CPU_DESCRIPTOR_HANDLE, clearFlags _D3D12_CLEAR_FLAGS, depth float32, stencil uint8, rects []_D3D12_RECT) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ClearRenderTargetView(i *_ID3D12GraphicsCommandList, pRenderTargetView _D3D12_CPU_DESCRIPTOR_HANDLE, colorRGBA [4]float32, rects []_D3D12_RECT) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Close(i *_ID3D12GraphicsCommandList) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_CopyTextureRegion(i *_ID3D12GraphicsCommandList, pDst unsafe.Pointer, dstX uint32, dstY uint32, dstZ uint32, pSrc unsafe.Pointer, pSrcBox *_D3D12_BOX) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_DrawIndexedInstanced(i *_ID3D12GraphicsCommandList, indexCountPerInstance uint32, instanceCount uint32, startIndexLocation uint32, baseVertexLocation int32, startInstanceLocation uint32) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetIndexBuffer(i *_ID3D12GraphicsCommandList, pView *_D3D12_INDEX_BUFFER_VIEW) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetPrimitiveTopology(i *_ID3D12GraphicsCommandList, primitiveTopology _D3D_PRIMITIVE_TOPOLOGY) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_IASetVertexBuffers(i *_ID3D12GraphicsCommandList, startSlot uint32, pViews []_D3D12_VERTEX_BUFFER_VIEW) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_OMSetRenderTargets(i *_ID3D12GraphicsCommandList, renderTargetDescriptors []_D3D12_CPU_DESCRIPTOR_HANDLE, rtsSingleHandleToDescriptorRange bool, pDepthStencilDescriptor *_D3D12_CPU_DESCRIPTOR_HANDLE) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_OMSetStencilRef(i *_ID3D12GraphicsCommandList, stencilRef uint32) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Release(i *_ID3D12GraphicsCommandList) uint32 {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_Reset(i *_ID3D12GraphicsCommandList, pAllocator *_ID3D12CommandAllocator, pInitialState *_ID3D12PipelineState) uintptr {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_ResourceBarrier(i *_ID3D12GraphicsCommandList, barriers []_D3D12_RESOURCE_BARRIER_Transition) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_RSSetViewports(i *_ID3D12GraphicsCommandList, viewports []_D3D12_VIEWPORT) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_RSSetScissorRects(i *_ID3D12GraphicsCommandList, rects []_D3D12_RECT) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetDescriptorHeaps(i *_ID3D12GraphicsCommandList, descriptorHeaps []*_ID3D12DescriptorHeap) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(i *_ID3D12GraphicsCommandList, rootParameterIndex uint32, baseDescriptor _D3D12_GPU_DESCRIPTOR_HANDLE) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetGraphicsRootSignature(i *_ID3D12GraphicsCommandList, pRootSignature *_ID3D12RootSignature) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func _ID3D12GraphicsCommandList_SetPipelineState(i *_ID3D12GraphicsCommandList, pPipelineState *_ID3D12PipelineState) {
|
||||
panic("not implemented")
|
||||
}
|
||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
// Copyright 2022 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const is64bit = unsafe.Sizeof(uintptr(0)) == 8
|
||||
|
||||
type handleError windows.Handle
|
||||
|
||||
func (h handleError) Error() string {
|
||||
return fmt.Sprintf("HANDLE(%d)", h)
|
||||
}
|
||||
|
||||
type (
|
||||
_BOOL int32
|
||||
)
|
||||
|
||||
func boolToUintptr(v bool) uintptr {
|
||||
if v {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr
|
||||
|
||||
var (
|
||||
// https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/appnotify/nf-appnotify-registerappstatechangenotification.md
|
||||
appnotify = windows.NewLazySystemDLL("API-MS-Win-Core-psm-appnotify-l1-1-0.dll")
|
||||
|
||||
procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification")
|
||||
)
|
||||
|
||||
func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, context unsafe.Pointer) (unsafe.Pointer, error) {
|
||||
cb := windows.NewCallback(routine)
|
||||
var registration unsafe.Pointer
|
||||
r, _, _ := procRegisterAppStateChangeNotification.Call(cb, uintptr(context), uintptr(unsafe.Pointer(®istration)))
|
||||
if windows.Errno(r) != windows.ERROR_SUCCESS {
|
||||
return nil, fmt.Errorf("directx: RegisterAppStateChangeNotification failed: %w", windows.Errno(r))
|
||||
}
|
||||
return registration, nil
|
||||
}
|
||||
Generated
Vendored
+1349
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+2077
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+180
@@ -0,0 +1,180 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Reference:
|
||||
// * https://github.com/wine-mirror/wine/blob/master/include/d3dcommon.idl
|
||||
|
||||
type _D3DCOMPILE uint32
|
||||
|
||||
const (
|
||||
_D3DCOMPILE_OPTIMIZATION_LEVEL3 _D3DCOMPILE = (1 << 15)
|
||||
)
|
||||
|
||||
type _D3D_DRIVER_TYPE int32
|
||||
|
||||
const (
|
||||
_D3D_DRIVER_TYPE_UNKNOWN _D3D_DRIVER_TYPE = iota
|
||||
_D3D_DRIVER_TYPE_HARDWARE
|
||||
_D3D_DRIVER_TYPE_REFERENCE
|
||||
_D3D_DRIVER_TYPE_NULL
|
||||
_D3D_DRIVER_TYPE_SOFTWARE
|
||||
_D3D_DRIVER_TYPE_WARP
|
||||
)
|
||||
|
||||
type _D3D_FEATURE_LEVEL int32
|
||||
|
||||
const (
|
||||
_D3D_FEATURE_LEVEL_9_1 _D3D_FEATURE_LEVEL = 0x9100
|
||||
_D3D_FEATURE_LEVEL_9_2 _D3D_FEATURE_LEVEL = 0x9200
|
||||
_D3D_FEATURE_LEVEL_9_3 _D3D_FEATURE_LEVEL = 0x9300
|
||||
_D3D_FEATURE_LEVEL_10_0 _D3D_FEATURE_LEVEL = 0xa000
|
||||
_D3D_FEATURE_LEVEL_10_1 _D3D_FEATURE_LEVEL = 0xa100
|
||||
_D3D_FEATURE_LEVEL_11_0 _D3D_FEATURE_LEVEL = 0xb000
|
||||
_D3D_FEATURE_LEVEL_11_1 _D3D_FEATURE_LEVEL = 0xb100
|
||||
_D3D_FEATURE_LEVEL_12_0 _D3D_FEATURE_LEVEL = 0xc000
|
||||
_D3D_FEATURE_LEVEL_12_1 _D3D_FEATURE_LEVEL = 0xc100
|
||||
_D3D_FEATURE_LEVEL_12_2 _D3D_FEATURE_LEVEL = 0xc200
|
||||
)
|
||||
|
||||
type _D3D_PRIMITIVE_TOPOLOGY int32
|
||||
|
||||
const (
|
||||
_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST _D3D_PRIMITIVE_TOPOLOGY = 4
|
||||
)
|
||||
|
||||
type _D3D_ROOT_SIGNATURE_VERSION int32
|
||||
|
||||
const (
|
||||
_D3D_ROOT_SIGNATURE_VERSION_1_0 _D3D_ROOT_SIGNATURE_VERSION = 0x1
|
||||
)
|
||||
|
||||
var (
|
||||
procD3DCompile *windows.LazyProc
|
||||
)
|
||||
|
||||
func init() {
|
||||
var d3dcompiler *windows.LazyDLL
|
||||
|
||||
// Enumerate possible DLL names for d3dcompiler_*.dll.
|
||||
// https://walbourn.github.io/hlsl-fxc-and-d3dcompile/
|
||||
for _, name := range []string{"d3dcompiler_47.dll", "d3dcompiler_46.dll", "d3dcompiler_43.dll"} {
|
||||
dll := windows.NewLazySystemDLL(name)
|
||||
if err := dll.Load(); err != nil {
|
||||
continue
|
||||
}
|
||||
d3dcompiler = dll
|
||||
break
|
||||
}
|
||||
|
||||
if d3dcompiler == nil {
|
||||
return
|
||||
}
|
||||
|
||||
procD3DCompile = d3dcompiler.NewProc("D3DCompile")
|
||||
}
|
||||
|
||||
func isD3DCompilerDLLAvailable() bool {
|
||||
return procD3DCompile != nil
|
||||
}
|
||||
|
||||
func _D3DCompile(srcData []byte, sourceName string, pDefines []_D3D_SHADER_MACRO, pInclude unsafe.Pointer, entryPoint string, target string, flags1 uint32, flags2 uint32) (*_ID3DBlob, error) {
|
||||
if !isD3DCompilerDLLAvailable() {
|
||||
return nil, fmt.Errorf("directx: d3dcompiler_*.dll is missing in this environment")
|
||||
}
|
||||
|
||||
// TODO: Define _ID3DInclude for pInclude, but is it possible in Go?
|
||||
|
||||
var defs unsafe.Pointer
|
||||
if len(pDefines) > 0 {
|
||||
defs = unsafe.Pointer(&pDefines[0])
|
||||
}
|
||||
sourceNameBytes := append([]byte(sourceName), 0)
|
||||
entryPointBytes := append([]byte(entryPoint), 0)
|
||||
targetBytes := append([]byte(target), 0)
|
||||
var code *_ID3DBlob
|
||||
var errorMsgs *_ID3DBlob
|
||||
r, _, _ := procD3DCompile.Call(
|
||||
uintptr(unsafe.Pointer(&srcData[0])), uintptr(len(srcData)), uintptr(unsafe.Pointer(&sourceNameBytes[0])),
|
||||
uintptr(defs), uintptr(unsafe.Pointer(pInclude)), uintptr(unsafe.Pointer(&entryPointBytes[0])),
|
||||
uintptr(unsafe.Pointer(&targetBytes[0])), uintptr(flags1), uintptr(flags2),
|
||||
uintptr(unsafe.Pointer(&code)), uintptr(unsafe.Pointer(&errorMsgs)))
|
||||
runtime.KeepAlive(pDefines)
|
||||
runtime.KeepAlive(pInclude)
|
||||
runtime.KeepAlive(sourceNameBytes)
|
||||
runtime.KeepAlive(entryPointBytes)
|
||||
runtime.KeepAlive(targetBytes)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
if errorMsgs != nil {
|
||||
defer errorMsgs.Release()
|
||||
return nil, fmt.Errorf("directx: D3DCompile failed: %s: %w", errorMsgs.String(), handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil, fmt.Errorf("directx: D3DCompile failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
|
||||
type _D3D_SHADER_MACRO struct {
|
||||
Name *byte
|
||||
Definition *byte
|
||||
}
|
||||
|
||||
type _ID3DBlob struct {
|
||||
vtbl *_ID3DBlob_Vtbl
|
||||
}
|
||||
|
||||
type _ID3DBlob_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
GetBufferPointer uintptr
|
||||
GetBufferSize uintptr
|
||||
}
|
||||
|
||||
func (i *_ID3DBlob) AddRef() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.AddRef, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *_ID3DBlob) GetBufferPointer() unsafe.Pointer {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetBufferPointer, 1, uintptr(unsafe.Pointer(i)),
|
||||
0, 0)
|
||||
return unsafe.Pointer(r)
|
||||
}
|
||||
|
||||
func (i *_ID3DBlob) GetBufferSize() uintptr {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetBufferSize, 1, uintptr(unsafe.Pointer(i)),
|
||||
0, 0)
|
||||
return r
|
||||
}
|
||||
|
||||
func (i *_ID3DBlob) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *_ID3DBlob) String() string {
|
||||
return string(unsafe.Slice((*byte)(unsafe.Pointer(i.GetBufferPointer())), i.GetBufferSize()))
|
||||
}
|
||||
Generated
Vendored
+622
@@ -0,0 +1,622 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type _DXGI_ALPHA_MODE uint32
|
||||
|
||||
const (
|
||||
_DXGI_ALPHA_MODE_UNSPECIFIED _DXGI_ALPHA_MODE = 0
|
||||
_DXGI_ALPHA_MODE_PREMULTIPLIED _DXGI_ALPHA_MODE = 1
|
||||
_DXGI_ALPHA_MODE_STRAIGHT _DXGI_ALPHA_MODE = 2
|
||||
_DXGI_ALPHA_MODE_IGNORE _DXGI_ALPHA_MODE = 3
|
||||
_DXGI_ALPHA_MODE_FORCE_DWORD _DXGI_ALPHA_MODE = 0xffffffff
|
||||
)
|
||||
|
||||
type _DXGI_COLOR_SPACE_TYPE int32
|
||||
|
||||
type _DXGI_FEATURE int32
|
||||
|
||||
const (
|
||||
_DXGI_FEATURE_PRESENT_ALLOW_TEARING _DXGI_FEATURE = 0
|
||||
)
|
||||
|
||||
type _DXGI_FORMAT int32
|
||||
|
||||
const (
|
||||
_DXGI_FORMAT_UNKNOWN _DXGI_FORMAT = 0
|
||||
_DXGI_FORMAT_R32G32B32A32_FLOAT _DXGI_FORMAT = 2
|
||||
_DXGI_FORMAT_R32G32_FLOAT _DXGI_FORMAT = 16
|
||||
_DXGI_FORMAT_R8G8B8A8_UNORM _DXGI_FORMAT = 28
|
||||
_DXGI_FORMAT_R32_UINT _DXGI_FORMAT = 42
|
||||
_DXGI_FORMAT_D24_UNORM_S8_UINT _DXGI_FORMAT = 45
|
||||
_DXGI_FORMAT_B8G8R8A8_UNORM _DXGI_FORMAT = 87
|
||||
)
|
||||
|
||||
type _DXGI_MODE_SCANLINE_ORDER int32
|
||||
|
||||
type _DXGI_MODE_SCALING int32
|
||||
|
||||
type _DXGI_PRESENT uint32
|
||||
|
||||
const (
|
||||
_DXGI_PRESENT_TEST _DXGI_PRESENT = 0x00000001
|
||||
_DXGI_PRESENT_ALLOW_TEARING _DXGI_PRESENT = 0x00000200
|
||||
)
|
||||
|
||||
type _DXGI_SCALING int32
|
||||
|
||||
type _DXGI_SWAP_CHAIN_FLAG int32
|
||||
|
||||
const (
|
||||
_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING _DXGI_SWAP_CHAIN_FLAG = 2048
|
||||
)
|
||||
|
||||
type _DXGI_SWAP_EFFECT int32
|
||||
|
||||
const (
|
||||
_DXGI_SWAP_EFFECT_DISCARD _DXGI_SWAP_EFFECT = 0
|
||||
_DXGI_SWAP_EFFECT_SEQUENTIAL _DXGI_SWAP_EFFECT = 1
|
||||
_DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL _DXGI_SWAP_EFFECT = 3
|
||||
_DXGI_SWAP_EFFECT_FLIP_DISCARD _DXGI_SWAP_EFFECT = 4
|
||||
)
|
||||
|
||||
type _DXGI_USAGE uint32
|
||||
|
||||
const (
|
||||
_DXGI_USAGE_RENDER_TARGET_OUTPUT _DXGI_USAGE = 1 << (1 + 4)
|
||||
)
|
||||
|
||||
const (
|
||||
_DXGI_ADAPTER_FLAG_SOFTWARE = 2
|
||||
|
||||
_DXGI_CREATE_FACTORY_DEBUG = 0x01
|
||||
|
||||
_DXGI_ERROR_NOT_FOUND = handleError(0x887A0002)
|
||||
|
||||
_DXGI_MWA_NO_ALT_ENTER = 0x2
|
||||
_DXGI_MWA_NO_WINDOW_CHANGES = 0x1
|
||||
)
|
||||
|
||||
var (
|
||||
_IID_IDXGIAdapter1 = windows.GUID{Data1: 0x29038f61, Data2: 0x3839, Data3: 0x4626, Data4: [...]byte{0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05}}
|
||||
_IID_IDXGIDevice = windows.GUID{Data1: 0x54ec77fa, Data2: 0x1377, Data3: 0x44e6, Data4: [...]byte{0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c}}
|
||||
_IID_IDXGIFactory = windows.GUID{Data1: 0x7b7166ec, Data2: 0x21c7, Data3: 0x44ae, Data4: [...]byte{0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69}}
|
||||
_IID_IDXGIFactory4 = windows.GUID{Data1: 0x1bc6ea02, Data2: 0xef36, Data3: 0x464f, Data4: [...]byte{0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a}}
|
||||
_IID_IDXGIFactory5 = windows.GUID{Data1: 0x7632e1f5, Data2: 0xee65, Data3: 0x4dca, Data4: [...]byte{0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d}}
|
||||
_IID_IDXGISwapChain4 = windows.GUID{Data1: 0x3d585d5a, Data2: 0xbd4a, Data3: 0x489e, Data4: [...]byte{0xb1, 0xf4, 0x3d, 0xbc, 0xb6, 0x45, 0x2f, 0xfb}}
|
||||
)
|
||||
|
||||
var (
|
||||
dxgi = windows.NewLazySystemDLL("dxgi.dll")
|
||||
|
||||
procCreateDXGIFactory = dxgi.NewProc("CreateDXGIFactory")
|
||||
)
|
||||
|
||||
func _CreateDXGIFactory() (*_IDXGIFactory, error) {
|
||||
var factory *_IDXGIFactory
|
||||
r, _, _ := procCreateDXGIFactory.Call(uintptr(unsafe.Pointer(&_IID_IDXGIFactory)), uintptr(unsafe.Pointer(&factory)))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: CreateDXGIFactory failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return factory, nil
|
||||
}
|
||||
|
||||
type _DXGI_ADAPTER_DESC1 struct {
|
||||
Description [128]uint16
|
||||
VendorId uint32
|
||||
DeviceId uint32
|
||||
SubSysId uint32
|
||||
Revision uint32
|
||||
DedicatedVideoMemory uint
|
||||
DedicatedSystemMemory uint
|
||||
SharedSystemMemory uint
|
||||
AdapterLuid _LUID
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type _DXGI_MODE_DESC struct {
|
||||
Width uint32
|
||||
Height uint32
|
||||
RefreshRate _DXGI_RATIONAL
|
||||
Format _DXGI_FORMAT
|
||||
ScanlineOrdering _DXGI_MODE_SCANLINE_ORDER
|
||||
Scaling _DXGI_MODE_SCALING
|
||||
}
|
||||
|
||||
type _DXGI_RATIONAL struct {
|
||||
Numerator uint32
|
||||
Denominator uint32
|
||||
}
|
||||
|
||||
type _DXGI_SWAP_CHAIN_FULLSCREEN_DESC struct {
|
||||
RefreshRate _DXGI_RATIONAL
|
||||
ScanlineOrdering _DXGI_MODE_SCANLINE_ORDER
|
||||
Scaling _DXGI_MODE_SCALING
|
||||
Windowed _BOOL
|
||||
}
|
||||
|
||||
type _DXGI_SAMPLE_DESC struct {
|
||||
Count uint32
|
||||
Quality uint32
|
||||
}
|
||||
|
||||
type _DXGI_SWAP_CHAIN_DESC struct {
|
||||
BufferDesc _DXGI_MODE_DESC
|
||||
SampleDesc _DXGI_SAMPLE_DESC
|
||||
BufferUsage _DXGI_USAGE
|
||||
BufferCount uint32
|
||||
OutputWindow windows.HWND
|
||||
Windowed _BOOL
|
||||
SwapEffect _DXGI_SWAP_EFFECT
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type _LUID struct {
|
||||
LowPart uint32
|
||||
HighPart int32
|
||||
}
|
||||
|
||||
type _IDXGIAdapter struct {
|
||||
vtbl *_IDXGIAdapter1_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIAdapter_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
EnumOutputs uintptr
|
||||
GetDesc uintptr
|
||||
CheckInterfaceSupport uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIAdapter) EnumOutputs(output uint32) (*_IDXGIOutput, error) {
|
||||
var pOutput *_IDXGIOutput
|
||||
r, _, _ := syscall.Syscall(i.vtbl.EnumOutputs, 3, uintptr(unsafe.Pointer(i)), uintptr(output), uintptr(unsafe.Pointer(&pOutput)))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIAdapter::EnumOutputs failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return pOutput, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIAdapter) GetParent(riid *windows.GUID) (unsafe.Pointer, error) {
|
||||
var v unsafe.Pointer
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetParent, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&v)))
|
||||
runtime.KeepAlive(riid)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIAdapter::GetParent failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIAdapter) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGIAdapter1 struct {
|
||||
vtbl *_IDXGIAdapter1_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIAdapter1_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
EnumOutputs uintptr
|
||||
GetDesc uintptr
|
||||
CheckInterfaceSupport uintptr
|
||||
GetDesc1 uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIAdapter1) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *_IDXGIAdapter1) GetDesc1() (*_DXGI_ADAPTER_DESC1, error) {
|
||||
var desc _DXGI_ADAPTER_DESC1
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetDesc1, 2, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&desc)), 0)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIAdapter1::GetDesc1 failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return &desc, nil
|
||||
}
|
||||
|
||||
type _IDXGIDevice struct {
|
||||
vtbl *_IDXGIDevice_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIDevice_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
GetAdapter uintptr
|
||||
CreateSurface uintptr
|
||||
QueryResourceResidency uintptr
|
||||
SetGPUThreadPriority uintptr
|
||||
GetGPUThreadPriority uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIDevice) GetAdapter() (*_IDXGIAdapter, error) {
|
||||
var adapter *_IDXGIAdapter
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetAdapter, 2, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&adapter)), 0)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIDevice::GetAdapter failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return adapter, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIDevice) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGIFactory struct {
|
||||
vtbl *_IDXGIFactory_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIFactory_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
EnumAdapters uintptr
|
||||
MakeWindowAssociation uintptr
|
||||
GetWindowAssociation uintptr
|
||||
CreateSwapChain uintptr
|
||||
CreateSoftwareAdapter uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory) CreateSwapChain(pDevice unsafe.Pointer, pDesc *_DXGI_SWAP_CHAIN_DESC) (*_IDXGISwapChain, error) {
|
||||
var swapChain *_IDXGISwapChain
|
||||
r, _, _ := syscall.Syscall6(i.vtbl.CreateSwapChain, 4, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(pDevice), uintptr(unsafe.Pointer(pDesc)), uintptr(unsafe.Pointer(&swapChain)),
|
||||
0, 0)
|
||||
runtime.KeepAlive(pDevice)
|
||||
runtime.KeepAlive(pDesc)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIFactory::CreateSwapChain failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return swapChain, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory) MakeWindowAssociation(windowHandle windows.HWND, flags uint32) error {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.MakeWindowAssociation, 3, uintptr(unsafe.Pointer(i)), uintptr(windowHandle), uintptr(flags))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: IDXGIFactory::MakeWIndowAssociation failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory) QueryInterface(riid *windows.GUID) (unsafe.Pointer, error) {
|
||||
var v unsafe.Pointer
|
||||
r, _, _ := syscall.Syscall(i.vtbl.QueryInterface, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&v)))
|
||||
runtime.KeepAlive(riid)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIFactory::QueryInterface failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGIFactory4 struct {
|
||||
vtbl *_IDXGIFactory4_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIFactory4_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
EnumAdapters uintptr
|
||||
MakeWindowAssociation uintptr
|
||||
GetWindowAssociation uintptr
|
||||
CreateSwapChain uintptr
|
||||
CreateSoftwareAdapter uintptr
|
||||
EnumAdapters1 uintptr
|
||||
IsCurrent uintptr
|
||||
IsWindowedStereoEnabled uintptr
|
||||
CreateSwapChainForHwnd uintptr
|
||||
CreateSwapChainForCoreWindow uintptr
|
||||
GetSharedResourceAdapterLuid uintptr
|
||||
RegisterStereoStatusWindow uintptr
|
||||
RegisterStereoStatusEvent uintptr
|
||||
UnregisterStereoStatus uintptr
|
||||
RegisterOcclusionStatusWindow uintptr
|
||||
RegisterOcclusionStatusEvent uintptr
|
||||
UnregisterOcclusionStatus uintptr
|
||||
CreateSwapChainForComposition uintptr
|
||||
GetCreationFlags uintptr
|
||||
EnumAdapterByLuid uintptr
|
||||
EnumWarpAdapter uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory4) EnumAdapters1(adapter uint32) (*_IDXGIAdapter1, error) {
|
||||
var ptr *_IDXGIAdapter1
|
||||
r, _, _ := syscall.Syscall(i.vtbl.EnumAdapters1, 3, uintptr(unsafe.Pointer(i)), uintptr(adapter), uintptr(unsafe.Pointer(&ptr)))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIFactory4::EnumAdapters1 failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return ptr, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory4) EnumWarpAdapter() (*_IDXGIAdapter1, error) {
|
||||
var ptr *_IDXGIAdapter1
|
||||
r, _, _ := syscall.Syscall(i.vtbl.EnumWarpAdapter, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&_IID_IDXGIAdapter1)), uintptr(unsafe.Pointer(&ptr)))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGIFactory4::EnumWarpAdapter failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return ptr, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory4) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGIFactory5 struct {
|
||||
vtbl *_IDXGIFactory5_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIFactory5_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
EnumAdapters uintptr
|
||||
MakeWindowAssociation uintptr
|
||||
GetWindowAssociation uintptr
|
||||
CreateSwapChain uintptr
|
||||
CreateSoftwareAdapter uintptr
|
||||
EnumAdapters1 uintptr
|
||||
IsCurrent uintptr
|
||||
IsWindowedStereoEnabled uintptr
|
||||
CreateSwapChainForHwnd uintptr
|
||||
CreateSwapChainForCoreWindow uintptr
|
||||
GetSharedResourceAdapterLuid uintptr
|
||||
RegisterStereoStatusWindow uintptr
|
||||
RegisterStereoStatusEvent uintptr
|
||||
UnregisterStereoStatus uintptr
|
||||
RegisterOcclusionStatusWindow uintptr
|
||||
RegisterOcclusionStatusEvent uintptr
|
||||
UnregisterOcclusionStatus uintptr
|
||||
CreateSwapChainForComposition uintptr
|
||||
GetCreationFlags uintptr
|
||||
EnumAdapterByLuid uintptr
|
||||
EnumWarpAdapter uintptr
|
||||
CheckFeatureSupport uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory5) CheckFeatureSupport(feature _DXGI_FEATURE, pFeatureSupportData unsafe.Pointer, featureSupportDataSize uint32) error {
|
||||
r, _, _ := syscall.Syscall6(i.vtbl.CheckFeatureSupport, 4, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(feature), uintptr(pFeatureSupportData), uintptr(featureSupportDataSize),
|
||||
0, 0)
|
||||
runtime.KeepAlive(pFeatureSupportData)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: IDXGIFactory5::CheckFeatureSupport failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *_IDXGIFactory5) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGIOutput struct {
|
||||
vtbl *_IDXGIOutput_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGIOutput_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
GetDesc uintptr
|
||||
GetDisplayModeList uintptr
|
||||
FindClosestMatchingMode uintptr
|
||||
WaitForVBlank uintptr
|
||||
TakeOwnership uintptr
|
||||
ReleaseOwnership uintptr
|
||||
GetGammaControlCapabilities uintptr
|
||||
SetGammaControl uintptr
|
||||
GetGammaControl uintptr
|
||||
SetDisplaySurface uintptr
|
||||
GetDisplaySurfaceData uintptr
|
||||
GetFrameStatistics uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGIOutput) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGISwapChain struct {
|
||||
vtbl *_IDXGISwapChain_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGISwapChain_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
GetDevice uintptr
|
||||
Present uintptr
|
||||
GetBuffer uintptr
|
||||
SetFullscreenState uintptr
|
||||
GetFullscreenState uintptr
|
||||
GetDesc uintptr
|
||||
ResizeBuffers uintptr
|
||||
ResizeTarget uintptr
|
||||
GetContainingOutput uintptr
|
||||
GetFrameStatistics uintptr
|
||||
GetLastPresentCount uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain) GetBuffer(buffer uint32, riid *windows.GUID) (unsafe.Pointer, error) {
|
||||
var resource unsafe.Pointer
|
||||
r, _, _ := syscall.Syscall6(i.vtbl.GetBuffer, 4, uintptr(unsafe.Pointer(i)),
|
||||
uintptr(buffer), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&resource)),
|
||||
0, 0)
|
||||
runtime.KeepAlive(riid)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGISwapChain::GetBuffer failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain) ResizeBuffers(bufferCount uint32, width uint32, height uint32, newFormat _DXGI_FORMAT, swapChainFlags uint32) error {
|
||||
r, _, _ := syscall.Syscall6(i.vtbl.ResizeBuffers, 6,
|
||||
uintptr(unsafe.Pointer(i)), uintptr(bufferCount), uintptr(width),
|
||||
uintptr(height), uintptr(newFormat), uintptr(swapChainFlags))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: IDXGISwapChain::ResizeBuffers failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain) Present(syncInterval uint32, flags uint32) (occluded bool, err error) {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Present, 3, uintptr(unsafe.Pointer(i)), uintptr(syncInterval), uintptr(flags))
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
// During a screen lock, Present fails (#2179).
|
||||
if uint32(r) == uint32(windows.DXGI_STATUS_OCCLUDED) {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("directx: IDXGISwapChain::Present failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain) QueryInterface(riid *windows.GUID) (unsafe.Pointer, error) {
|
||||
var v unsafe.Pointer
|
||||
r, _, _ := syscall.Syscall(i.vtbl.QueryInterface, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&v)))
|
||||
runtime.KeepAlive(riid)
|
||||
if uint32(r) != uint32(windows.S_OK) {
|
||||
return nil, fmt.Errorf("directx: IDXGISwapChain::QueryInterface failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type _IDXGISwapChain4 struct {
|
||||
vtbl *_IDXGISwapChain4_Vtbl
|
||||
}
|
||||
|
||||
type _IDXGISwapChain4_Vtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
|
||||
SetPrivateData uintptr
|
||||
SetPrivateDataInterface uintptr
|
||||
GetPrivateData uintptr
|
||||
GetParent uintptr
|
||||
GetDevice uintptr
|
||||
Present uintptr
|
||||
GetBuffer uintptr
|
||||
SetFullscreenState uintptr
|
||||
GetFullscreenState uintptr
|
||||
GetDesc uintptr
|
||||
ResizeBuffers uintptr
|
||||
ResizeTarget uintptr
|
||||
GetContainingOutput uintptr
|
||||
GetFrameStatistics uintptr
|
||||
GetLastPresentCount uintptr
|
||||
GetDesc1 uintptr
|
||||
GetFullscreenDesc uintptr
|
||||
GetHwnd uintptr
|
||||
GetCoreWindow uintptr
|
||||
Present1 uintptr
|
||||
IsTemporaryMonoSupported uintptr
|
||||
GetRestrictToOutput uintptr
|
||||
SetBackgroundColor uintptr
|
||||
GetBackgroundColor uintptr
|
||||
SetRotation uintptr
|
||||
GetRotation uintptr
|
||||
|
||||
SetSourceSize uintptr
|
||||
GetSourceSize uintptr
|
||||
SetMaximumFrameLatency uintptr
|
||||
GetMaximumFrameLatency uintptr
|
||||
GetFrameLatencyWaitableObject uintptr
|
||||
SetMatrixTransform uintptr
|
||||
GetMatrixTransform uintptr
|
||||
GetCurrentBackBufferIndex uintptr
|
||||
CheckColorSpaceSupport uintptr
|
||||
SetColorSpace1 uintptr
|
||||
ResizeBuffers1 uintptr
|
||||
SetHDRMetaData uintptr
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain4) GetCurrentBackBufferIndex() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.GetCurrentBackBufferIndex, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *_IDXGISwapChain4) Release() uint32 {
|
||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||
return uint32(r)
|
||||
}
|
||||
Generated
Vendored
+730
@@ -0,0 +1,730 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"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,
|
||||
},
|
||||
}
|
||||
|
||||
func blendFactorToBlend11(f graphicsdriver.BlendFactor, alpha bool) _D3D11_BLEND {
|
||||
switch f {
|
||||
case graphicsdriver.BlendFactorZero:
|
||||
return _D3D11_BLEND_ZERO
|
||||
case graphicsdriver.BlendFactorOne:
|
||||
return _D3D11_BLEND_ONE
|
||||
case graphicsdriver.BlendFactorSourceColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_SRC_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusSourceColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_INV_SRC_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_INV_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorSourceAlpha:
|
||||
return _D3D11_BLEND_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusSourceAlpha:
|
||||
return _D3D11_BLEND_INV_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorDestinationColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_DEST_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_INV_DEST_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_INV_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorDestinationAlpha:
|
||||
return _D3D11_BLEND_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationAlpha:
|
||||
return _D3D11_BLEND_INV_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorSourceAlphaSaturated:
|
||||
return _D3D11_BLEND_SRC_ALPHA_SAT
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend factor: %d", f))
|
||||
}
|
||||
}
|
||||
|
||||
func blendOperationToBlendOp11(o graphicsdriver.BlendOperation) _D3D11_BLEND_OP {
|
||||
switch o {
|
||||
case graphicsdriver.BlendOperationAdd:
|
||||
return _D3D11_BLEND_OP_ADD
|
||||
case graphicsdriver.BlendOperationSubtract:
|
||||
return _D3D11_BLEND_OP_SUBTRACT
|
||||
case graphicsdriver.BlendOperationReverseSubtract:
|
||||
return _D3D11_BLEND_OP_REV_SUBTRACT
|
||||
case graphicsdriver.BlendOperationMin:
|
||||
return _D3D11_BLEND_OP_MIN
|
||||
case graphicsdriver.BlendOperationMax:
|
||||
return _D3D11_BLEND_OP_MAX
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend operation: %d", o))
|
||||
}
|
||||
}
|
||||
|
||||
type blendStateKey struct {
|
||||
blend graphicsdriver.Blend
|
||||
writeMask uint8
|
||||
}
|
||||
|
||||
type graphics11 struct {
|
||||
graphicsInfra *graphicsInfra
|
||||
|
||||
featureLevel _D3D_FEATURE_LEVEL
|
||||
|
||||
device *_ID3D11Device
|
||||
deviceContext *_ID3D11DeviceContext
|
||||
|
||||
images map[graphicsdriver.ImageID]*image11
|
||||
screenImage *image11
|
||||
nextImageID graphicsdriver.ImageID
|
||||
|
||||
shaders map[graphicsdriver.ShaderID]*shader11
|
||||
nextShaderID graphicsdriver.ShaderID
|
||||
|
||||
vertexBuffer *_ID3D11Buffer
|
||||
vertexBufferSizeInBytes uint32
|
||||
|
||||
indexBuffer *_ID3D11Buffer
|
||||
indexBufferSizeInBytes uint32
|
||||
|
||||
rasterizerState *_ID3D11RasterizerState
|
||||
samplerState *_ID3D11SamplerState
|
||||
blendStates map[blendStateKey]*_ID3D11BlendState
|
||||
depthStencilStates map[stencilMode]*_ID3D11DepthStencilState
|
||||
|
||||
vsyncEnabled bool
|
||||
window windows.HWND
|
||||
|
||||
newScreenWidth int
|
||||
newScreenHeight int
|
||||
}
|
||||
|
||||
func newGraphics11(useWARP bool, useDebugLayer bool) (gr11 *graphics11, ferr error) {
|
||||
g := &graphics11{
|
||||
vsyncEnabled: true,
|
||||
}
|
||||
|
||||
driverType := _D3D_DRIVER_TYPE_HARDWARE
|
||||
if useWARP {
|
||||
driverType = _D3D_DRIVER_TYPE_WARP
|
||||
}
|
||||
|
||||
var flags _D3D11_CREATE_DEVICE_FLAG
|
||||
if useDebugLayer {
|
||||
flags |= _D3D11_CREATE_DEVICE_DEBUG
|
||||
}
|
||||
|
||||
// Avoid _D3D_FEATURE_LEVEL_11_1 as DirectX 11.0 doesn't recognize this.
|
||||
// Avoid _D3D_FEATURE_LEVEL_9_* for some shaders features (#1431).
|
||||
featureLevels := []_D3D_FEATURE_LEVEL{
|
||||
_D3D_FEATURE_LEVEL_11_0,
|
||||
_D3D_FEATURE_LEVEL_10_1,
|
||||
_D3D_FEATURE_LEVEL_10_0,
|
||||
}
|
||||
|
||||
// Apparently, adapter must be nil if the driver type is not unknown. This is not documented explicitly.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice
|
||||
d, fl, ctx, err := _D3D11CreateDevice(nil, driverType, 0, uint32(flags), featureLevels, true, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.device = (*_ID3D11Device)(d)
|
||||
g.featureLevel = fl
|
||||
g.deviceContext = (*_ID3D11DeviceContext)(ctx)
|
||||
|
||||
// Get IDXGIFactory from the current device and use it, instead of CreateDXGIFactory.
|
||||
// Or, MakeWindowAssociation doesn't work well (#2661).
|
||||
dd, err := g.device.QueryInterface(&_IID_IDXGIDevice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dxgiDevice := (*_IDXGIDevice)(dd)
|
||||
defer dxgiDevice.Release()
|
||||
|
||||
dxgiAdapter, err := dxgiDevice.GetAdapter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dxgiAdapter.Release()
|
||||
|
||||
df, err := dxgiAdapter.GetParent(&_IID_IDXGIFactory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dxgiFactory := (*_IDXGIFactory)(df)
|
||||
|
||||
gi, err := newGraphicsInfra(dxgiFactory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.graphicsInfra = gi
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
g.graphicsInfra.release()
|
||||
g.graphicsInfra = nil
|
||||
}
|
||||
}()
|
||||
|
||||
g.deviceContext.IASetPrimitiveTopology(_D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
|
||||
|
||||
// Set the rasterizer state.
|
||||
if g.rasterizerState == nil {
|
||||
rs, err := g.device.CreateRasterizerState(&_D3D11_RASTERIZER_DESC{
|
||||
FillMode: _D3D11_FILL_SOLID,
|
||||
CullMode: _D3D11_CULL_NONE,
|
||||
FrontCounterClockwise: 0,
|
||||
DepthBias: 0,
|
||||
DepthBiasClamp: 0,
|
||||
SlopeScaledDepthBias: 0,
|
||||
DepthClipEnable: 0,
|
||||
ScissorEnable: 1,
|
||||
MultisampleEnable: 0,
|
||||
AntialiasedLineEnable: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.rasterizerState = rs
|
||||
}
|
||||
g.deviceContext.RSSetState(g.rasterizerState)
|
||||
|
||||
// Set the sampler state.
|
||||
if g.samplerState == nil {
|
||||
s, err := g.device.CreateSamplerState(&_D3D11_SAMPLER_DESC{
|
||||
Filter: _D3D11_FILTER_MIN_MAG_MIP_POINT,
|
||||
AddressU: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
AddressV: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
AddressW: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
ComparisonFunc: _D3D11_COMPARISON_NEVER,
|
||||
MinLOD: -math.MaxFloat32,
|
||||
MaxLOD: math.MaxFloat32,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.samplerState = s
|
||||
}
|
||||
g.deviceContext.PSSetSamplers(0, []*_ID3D11SamplerState{g.samplerState})
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) Initialize() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) Begin() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) End(present bool) error {
|
||||
if !present {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := g.graphicsInfra.present(g.vsyncEnabled); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if g.newScreenWidth != 0 && g.newScreenHeight != 0 {
|
||||
if g.screenImage != nil {
|
||||
// ResizeBuffer requires all the related resources released,
|
||||
// so release the swapchain's buffer.
|
||||
// Do not dispose the screen image itself since the image's ID is still used.
|
||||
g.screenImage.disposeBuffers()
|
||||
}
|
||||
|
||||
if err := g.graphicsInfra.resizeSwapChain(g.newScreenWidth, g.newScreenHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t, err := g.graphicsInfra.getBuffer(0, &_IID_ID3D11Texture2D)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.screenImage.width = g.newScreenWidth
|
||||
g.screenImage.height = g.newScreenHeight
|
||||
g.screenImage.texture = (*_ID3D11Texture2D)(t)
|
||||
|
||||
g.newScreenWidth = 0
|
||||
g.newScreenHeight = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) SetWindow(window uintptr) {
|
||||
g.window = windows.HWND(window)
|
||||
// TODO: need to update the swap chain?
|
||||
}
|
||||
|
||||
func (g *graphics11) SetTransparent(transparent bool) {
|
||||
// TODO: Implement this?
|
||||
}
|
||||
|
||||
func (g *graphics11) SetVertices(vertices []float32, indices []uint32) error {
|
||||
if size := pow2(uint32(len(vertices)) * uint32(unsafe.Sizeof(vertices[0]))); g.vertexBufferSizeInBytes < size {
|
||||
if g.vertexBuffer != nil {
|
||||
g.vertexBuffer.Release()
|
||||
g.vertexBuffer = nil
|
||||
}
|
||||
b, err := g.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: size,
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_VERTEX_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.vertexBuffer = b
|
||||
g.vertexBufferSizeInBytes = size
|
||||
g.deviceContext.IASetVertexBuffers(0, []*_ID3D11Buffer{g.vertexBuffer},
|
||||
[]uint32{graphics.VertexFloatCount * uint32(unsafe.Sizeof(vertices[0]))}, []uint32{0})
|
||||
}
|
||||
if size := pow2(uint32(len(indices)) * uint32(unsafe.Sizeof(indices[0]))); g.indexBufferSizeInBytes < size {
|
||||
if g.indexBuffer != nil {
|
||||
g.indexBuffer.Release()
|
||||
g.indexBuffer = nil
|
||||
}
|
||||
b, err := g.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: size,
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_INDEX_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.indexBuffer = b
|
||||
g.indexBufferSizeInBytes = size
|
||||
g.deviceContext.IASetIndexBuffer(g.indexBuffer, _DXGI_FORMAT_R32_UINT, 0)
|
||||
}
|
||||
|
||||
// Copy the vertices data.
|
||||
{
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := g.deviceContext.Map(unsafe.Pointer(g.vertexBuffer), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*float32)(mapped.pData), len(vertices)), vertices)
|
||||
g.deviceContext.Unmap(unsafe.Pointer(g.vertexBuffer), 0)
|
||||
}
|
||||
|
||||
// Copy the indices data.
|
||||
{
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := g.deviceContext.Map(unsafe.Pointer(g.indexBuffer), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*uint32)(mapped.pData), len(indices)), indices)
|
||||
g.deviceContext.Unmap(unsafe.Pointer(g.indexBuffer), 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
t, err := g.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(graphics.InternalImageSize(width)),
|
||||
Height: uint32(graphics.InternalImageSize(height)),
|
||||
MipLevels: 1, // 0 doesn't work when shrinking the image.
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_DEFAULT,
|
||||
BindFlags: uint32(_D3D11_BIND_SHADER_RESOURCE | _D3D11_BIND_RENDER_TARGET),
|
||||
CPUAccessFlags: 0,
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := &image11{
|
||||
graphics: g,
|
||||
id: g.genNextImageID(),
|
||||
width: width,
|
||||
height: height,
|
||||
texture: t,
|
||||
}
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) NewScreenFramebufferImage(width, height int) (graphicsdriver.Image, error) {
|
||||
imageWidth := width
|
||||
imageHeight := height
|
||||
if g.screenImage != nil {
|
||||
imageWidth = g.screenImage.width
|
||||
imageHeight = g.screenImage.height
|
||||
g.screenImage.Dispose()
|
||||
g.screenImage = nil
|
||||
}
|
||||
|
||||
if g.graphicsInfra.isSwapChainInited() {
|
||||
g.newScreenWidth, g.newScreenHeight = width, height
|
||||
} else {
|
||||
if err := g.graphicsInfra.initSwapChain(width, height, unsafe.Pointer(g.device), g.window); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
t, err := g.graphicsInfra.getBuffer(0, &_IID_ID3D11Texture2D)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := &image11{
|
||||
graphics: g,
|
||||
id: g.genNextImageID(),
|
||||
width: imageWidth,
|
||||
height: imageHeight,
|
||||
screen: true,
|
||||
texture: (*_ID3D11Texture2D)(t),
|
||||
}
|
||||
g.addImage(i)
|
||||
g.screenImage = i
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) addImage(img *image11) {
|
||||
if g.images == nil {
|
||||
g.images = map[graphicsdriver.ImageID]*image11{}
|
||||
}
|
||||
if _, ok := g.images[img.id]; ok {
|
||||
panic(fmt.Sprintf("directx: image ID %d was already registered", img.id))
|
||||
}
|
||||
g.images[img.id] = img
|
||||
}
|
||||
|
||||
func (g *graphics11) removeImage(image *image11) {
|
||||
delete(g.images, image.id)
|
||||
}
|
||||
|
||||
func (g *graphics11) SetVsyncEnabled(enabled bool) {
|
||||
g.vsyncEnabled = enabled
|
||||
}
|
||||
|
||||
func (g *graphics11) NeedsClearingScreen() bool {
|
||||
// TODO: Confirm this is really true.
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *graphics11) MaxImageSize() int {
|
||||
switch g.featureLevel {
|
||||
case _D3D_FEATURE_LEVEL_10_0:
|
||||
return 8192
|
||||
case _D3D_FEATURE_LEVEL_10_1:
|
||||
return 8192
|
||||
case _D3D_FEATURE_LEVEL_11_0:
|
||||
return 16384
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid feature level: 0x%x", g.featureLevel))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *graphics11) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
vs, ps, offsets := hlsl.Compile(program)
|
||||
vsh, psh, err := compileShader(vs, ps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &shader11{
|
||||
graphics: g,
|
||||
id: g.genNextShaderID(),
|
||||
uniformTypes: program.Uniforms,
|
||||
uniformOffsets: offsets,
|
||||
vertexShaderBlob: vsh,
|
||||
pixelShaderBlob: psh,
|
||||
}
|
||||
g.addShader(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) addShader(s *shader11) {
|
||||
if g.shaders == nil {
|
||||
g.shaders = map[graphicsdriver.ShaderID]*shader11{}
|
||||
}
|
||||
if _, ok := g.shaders[s.id]; ok {
|
||||
panic(fmt.Sprintf("directx: shader ID %d was already registered", s.id))
|
||||
}
|
||||
g.shaders[s.id] = s
|
||||
}
|
||||
|
||||
func (g *graphics11) removeShader(s *shader11) {
|
||||
s.disposeImpl()
|
||||
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 {
|
||||
// Remove bound textures first. This is needed to avoid warnings on the debugger.
|
||||
g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil)
|
||||
srvs := [graphics.ShaderImageCount]*_ID3D11ShaderResourceView{}
|
||||
g.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||
|
||||
dst := g.images[dstID]
|
||||
var srcs [graphics.ShaderImageCount]*image11
|
||||
for i, id := range srcIDs {
|
||||
img := g.images[id]
|
||||
if img == nil {
|
||||
continue
|
||||
}
|
||||
srcs[i] = img
|
||||
}
|
||||
|
||||
w, h := dst.internalSize()
|
||||
g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{
|
||||
{
|
||||
TopLeftX: 0,
|
||||
TopLeftY: 0,
|
||||
Width: float32(w),
|
||||
Height: float32(h),
|
||||
MinDepth: 0,
|
||||
MaxDepth: 1,
|
||||
},
|
||||
})
|
||||
|
||||
if err := dst.setAsRenderTarget(fillRule != graphicsdriver.FillAll); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the shader parameters.
|
||||
shader := g.shaders[shaderID]
|
||||
if err := shader.use(uniforms, srcs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fillRule == graphicsdriver.FillAll {
|
||||
bs, err := g.blendState(blend, noStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
|
||||
dss, err := g.depthStencilState(noStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
}
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.deviceContext.RSSetScissorRects([]_D3D11_RECT{
|
||||
{
|
||||
left: int32(dstRegion.Region.Min.X),
|
||||
top: int32(dstRegion.Region.Min.Y),
|
||||
right: int32(dstRegion.Region.Max.X),
|
||||
bottom: int32(dstRegion.Region.Max.Y),
|
||||
},
|
||||
})
|
||||
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
case graphicsdriver.NonZero:
|
||||
bs, err := g.blendState(blend, incrementStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
dss, err := g.depthStencilState(incrementStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
case graphicsdriver.EvenOdd:
|
||||
bs, err := g.blendState(blend, invertStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
dss, err := g.depthStencilState(invertStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
bs, err := g.blendState(blend, drawWithStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
dss, err := g.depthStencilState(drawWithStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
}
|
||||
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) genNextImageID() graphicsdriver.ImageID {
|
||||
g.nextImageID++
|
||||
return g.nextImageID
|
||||
}
|
||||
|
||||
func (g *graphics11) genNextShaderID() graphicsdriver.ShaderID {
|
||||
g.nextShaderID++
|
||||
return g.nextShaderID
|
||||
}
|
||||
|
||||
func (g *graphics11) blendState(blend graphicsdriver.Blend, stencilMode stencilMode) (*_ID3D11BlendState, error) {
|
||||
var writeMask uint8
|
||||
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||
writeMask = uint8(_D3D11_COLOR_WRITE_ENABLE_ALL)
|
||||
}
|
||||
|
||||
key := blendStateKey{
|
||||
blend: blend,
|
||||
writeMask: writeMask,
|
||||
}
|
||||
if bs, ok := g.blendStates[key]; ok {
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
bs, err := g.device.CreateBlendState(&_D3D11_BLEND_DESC{
|
||||
AlphaToCoverageEnable: 0,
|
||||
IndependentBlendEnable: 0,
|
||||
RenderTarget: [8]_D3D11_RENDER_TARGET_BLEND_DESC{
|
||||
{
|
||||
BlendEnable: 1,
|
||||
SrcBlend: blendFactorToBlend11(blend.BlendFactorSourceRGB, false),
|
||||
DestBlend: blendFactorToBlend11(blend.BlendFactorDestinationRGB, false),
|
||||
BlendOp: blendOperationToBlendOp11(blend.BlendOperationRGB),
|
||||
SrcBlendAlpha: blendFactorToBlend11(blend.BlendFactorSourceAlpha, true),
|
||||
DestBlendAlpha: blendFactorToBlend11(blend.BlendFactorDestinationAlpha, true),
|
||||
BlendOpAlpha: blendOperationToBlendOp11(blend.BlendOperationAlpha),
|
||||
RenderTargetWriteMask: writeMask,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if g.blendStates == nil {
|
||||
g.blendStates = map[blendStateKey]*_ID3D11BlendState{}
|
||||
}
|
||||
g.blendStates[key] = bs
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) depthStencilState(mode stencilMode) (*_ID3D11DepthStencilState, error) {
|
||||
if s, ok := g.depthStencilStates[mode]; ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
desc := &_D3D11_DEPTH_STENCIL_DESC{
|
||||
DepthEnable: 0,
|
||||
DepthWriteMask: _D3D11_DEPTH_WRITE_MASK_ALL,
|
||||
DepthFunc: _D3D11_COMPARISON_LESS,
|
||||
StencilEnable: 0,
|
||||
StencilReadMask: _D3D11_DEFAULT_STENCIL_READ_MASK,
|
||||
StencilWriteMask: _D3D11_DEFAULT_STENCIL_WRITE_MASK,
|
||||
FrontFace: _D3D11_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D11_COMPARISON_ALWAYS,
|
||||
},
|
||||
BackFace: _D3D11_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D11_COMPARISON_ALWAYS,
|
||||
},
|
||||
}
|
||||
switch mode {
|
||||
case incrementStencil:
|
||||
desc.StencilEnable = 1
|
||||
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INCR
|
||||
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_DECR
|
||||
case invertStencil:
|
||||
desc.StencilEnable = 1
|
||||
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||
case drawWithStencil:
|
||||
desc.StencilEnable = 1
|
||||
desc.FrontFace.StencilFunc = _D3D11_COMPARISON_NOT_EQUAL
|
||||
desc.BackFace.StencilFunc = _D3D11_COMPARISON_NOT_EQUAL
|
||||
}
|
||||
|
||||
s, err := g.device.CreateDepthStencilState(desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if g.depthStencilStates == nil {
|
||||
g.depthStencilStates = map[stencilMode]*_ID3D11DepthStencilState{}
|
||||
}
|
||||
g.depthStencilStates[mode] = s
|
||||
return s, nil
|
||||
}
|
||||
Generated
Vendored
+1176
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+374
@@ -0,0 +1,374 @@
|
||||
// Copyright 2022 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 directx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/winver"
|
||||
)
|
||||
|
||||
type stencilMode int
|
||||
|
||||
const (
|
||||
noStencil stencilMode = iota
|
||||
incrementStencil
|
||||
invertStencil
|
||||
drawWithStencil
|
||||
)
|
||||
|
||||
const frameCount = 2
|
||||
|
||||
func pow2(x uint32) uint32 {
|
||||
if x > (math.MaxUint32+1)/2 {
|
||||
return math.MaxUint32
|
||||
}
|
||||
|
||||
var p2 uint32 = 1
|
||||
for p2 < x {
|
||||
p2 *= 2
|
||||
}
|
||||
return p2
|
||||
}
|
||||
|
||||
func parseFeatureLevel(str string) (_D3D_FEATURE_LEVEL, bool) {
|
||||
switch str {
|
||||
case "11_0":
|
||||
return _D3D_FEATURE_LEVEL_11_0, true
|
||||
case "11_1":
|
||||
return _D3D_FEATURE_LEVEL_11_1, true
|
||||
case "12_0":
|
||||
return _D3D_FEATURE_LEVEL_12_0, true
|
||||
case "12_1":
|
||||
return _D3D_FEATURE_LEVEL_12_1, true
|
||||
case "12_2":
|
||||
return _D3D_FEATURE_LEVEL_12_2, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for DirectX.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
if !isD3DCompilerDLLAvailable() {
|
||||
return nil, fmt.Errorf("directx: d3dcompiler_*.dll is missing in this environment")
|
||||
}
|
||||
|
||||
var useWARP bool
|
||||
var useDebugLayer bool
|
||||
version := 11
|
||||
|
||||
// Specify the feature level 11 by default.
|
||||
// Some old cards don't work well with the default feature level (#2447, #2486).
|
||||
featureLevel := _D3D_FEATURE_LEVEL_11_0
|
||||
|
||||
// Parse a special environment variable for backward compatibility.
|
||||
if env := os.Getenv("EBITENGINE_DIRECTX_FEATURE_LEVEL"); env != "" {
|
||||
if fl, ok := parseFeatureLevel(env); ok {
|
||||
featureLevel = fl
|
||||
}
|
||||
}
|
||||
|
||||
env := os.Getenv("EBITENGINE_DIRECTX")
|
||||
if env == "" {
|
||||
// For backward compatibility, read the EBITEN_ version.
|
||||
env = os.Getenv("EBITEN_DIRECTX")
|
||||
}
|
||||
|
||||
for _, t := range strings.Split(env, ",") {
|
||||
t := strings.TrimSpace(t)
|
||||
switch {
|
||||
case t == "warp":
|
||||
// TODO: Is WARP available on Xbox?
|
||||
useWARP = true
|
||||
case t == "debug":
|
||||
useDebugLayer = true
|
||||
case strings.HasPrefix(t, "version="):
|
||||
v, err := strconv.Atoi(t[len("version="):])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
version = v
|
||||
case strings.HasPrefix(t, "featurelevel="):
|
||||
fl, ok := parseFeatureLevel(t[len("featurelevel="):])
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
featureLevel = fl
|
||||
}
|
||||
}
|
||||
|
||||
// On Xbox, only DirectX 12 is available.
|
||||
if microsoftgdk.IsXbox() {
|
||||
version = 12
|
||||
}
|
||||
|
||||
switch version {
|
||||
case 11:
|
||||
g, err := newGraphics11(useWARP, useDebugLayer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return g, nil
|
||||
case 12:
|
||||
g, err := newGraphics12(useWARP, useDebugLayer, featureLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return g, nil
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: unexpected DirectX version: %d", version))
|
||||
}
|
||||
}
|
||||
|
||||
type graphicsInfra struct {
|
||||
factory *_IDXGIFactory
|
||||
swapChain *_IDXGISwapChain
|
||||
swapChain4 *_IDXGISwapChain4
|
||||
|
||||
allowTearing bool
|
||||
|
||||
// occluded reports whether the screen is invisible or not.
|
||||
occluded bool
|
||||
|
||||
// lastTime is the last time for rendering.
|
||||
lastTime time.Time
|
||||
|
||||
bufferCount int
|
||||
}
|
||||
|
||||
// newGraphicsInfra takes the ownership of the given factory.
|
||||
func newGraphicsInfra(factory *_IDXGIFactory) (*graphicsInfra, error) {
|
||||
g := &graphicsInfra{
|
||||
factory: factory,
|
||||
}
|
||||
runtime.SetFinalizer(g, (*graphicsInfra).release)
|
||||
|
||||
if f, err := g.factory.QueryInterface(&_IID_IDXGIFactory5); err == nil && f != nil {
|
||||
factory := (*_IDXGIFactory5)(f)
|
||||
defer factory.Release()
|
||||
|
||||
var allowTearing int32
|
||||
if err := factory.CheckFeatureSupport(_DXGI_FEATURE_PRESENT_ALLOW_TEARING, unsafe.Pointer(&allowTearing), uint32(unsafe.Sizeof(allowTearing))); err == nil && allowTearing != 0 {
|
||||
g.allowTearing = true
|
||||
}
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) release() {
|
||||
if g.factory != nil {
|
||||
g.factory.Release()
|
||||
g.factory = nil
|
||||
}
|
||||
if g.swapChain != nil {
|
||||
g.swapChain.Release()
|
||||
g.swapChain = nil
|
||||
}
|
||||
if g.swapChain4 != nil {
|
||||
g.swapChain4.Release()
|
||||
g.swapChain4 = nil
|
||||
}
|
||||
}
|
||||
|
||||
// appendAdapters appends found adapters to the given adapters.
|
||||
// Releasing them is the caller's responsibility.
|
||||
//
|
||||
// warpForDX12 is valid only for DirectX 12.
|
||||
func (g *graphicsInfra) appendAdapters(adapters []*_IDXGIAdapter1, warpForDX12 bool) ([]*_IDXGIAdapter1, error) {
|
||||
f, err := g.factory.QueryInterface(&_IID_IDXGIFactory4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f == nil {
|
||||
return nil, fmt.Errorf("directx: IID_IDXGIFactory4 was not available")
|
||||
}
|
||||
factory4 := (*_IDXGIFactory4)(f)
|
||||
defer factory4.Release()
|
||||
|
||||
if warpForDX12 {
|
||||
a, err := factory4.EnumWarpAdapter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adapters = append(adapters, a)
|
||||
return adapters, nil
|
||||
}
|
||||
|
||||
for i := uint32(0); ; i++ {
|
||||
a, err := factory4.EnumAdapters1(i)
|
||||
if errors.Is(err, _DXGI_ERROR_NOT_FOUND) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
adapters = append(adapters, a)
|
||||
}
|
||||
|
||||
return adapters, nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) isSwapChainInited() bool {
|
||||
return g.swapChain != nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) initSwapChain(width, height int, device unsafe.Pointer, window windows.HWND) (ferr error) {
|
||||
if g.swapChain != nil {
|
||||
return fmt.Errorf("directx: swap chain must not be initialized at initSwapChain, but is already done")
|
||||
}
|
||||
|
||||
// Create a swap chain.
|
||||
//
|
||||
// DXGI_ALPHA_MODE_PREMULTIPLIED doesn't work with a HWND well.
|
||||
//
|
||||
// IDXGIFactory::CreateSwapChain: Alpha blended swapchains must be created with CreateSwapChainForComposition,
|
||||
// or CreateSwapChainForCoreWindow with the DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER flag
|
||||
//
|
||||
// Use *_SEQUENTIAL swap effects to follow the Mozilla way:
|
||||
// https://github.com/mozilla/gecko-dev/blob/0907529ff72c456ddb47839f5f7ba16291f28dce/gfx/layers/d3d11/CompositorD3D11.cpp#L167-L254
|
||||
desc := &_DXGI_SWAP_CHAIN_DESC{
|
||||
BufferDesc: _DXGI_MODE_DESC{
|
||||
Width: uint32(width),
|
||||
Height: uint32(height),
|
||||
Format: _DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
},
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
BufferUsage: _DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
BufferCount: frameCount,
|
||||
OutputWindow: window,
|
||||
Windowed: 1,
|
||||
SwapEffect: _DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
|
||||
}
|
||||
|
||||
// DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL/DISCARD are not supported for older Windows than 10 or DirectX 12.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect
|
||||
if !winver.IsWindows10OrGreater() {
|
||||
desc.SwapEffect = _DXGI_SWAP_EFFECT_SEQUENTIAL
|
||||
// With the non-flip (bitblt) mode, the buffer count should be 1. See also:
|
||||
// * https://bugzilla.mozilla.org/show_bug.cgi?id=1419293#c18
|
||||
// * https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-flip-model
|
||||
desc.BufferCount = 1
|
||||
}
|
||||
|
||||
g.bufferCount = int(desc.BufferCount)
|
||||
|
||||
if g.allowTearing {
|
||||
desc.Flags |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
||||
}
|
||||
s, err := g.factory.CreateSwapChain(device, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.swapChain = s
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
g.release()
|
||||
}
|
||||
}()
|
||||
|
||||
if s4, err := g.swapChain.QueryInterface(&_IID_IDXGISwapChain4); err == nil && s4 != nil {
|
||||
g.swapChain4 = (*_IDXGISwapChain4)(s4)
|
||||
}
|
||||
|
||||
// MakeWindowAssociation should be called after swap chain creation.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgifactory-makewindowassociation
|
||||
if err := g.factory.MakeWindowAssociation(window, _DXGI_MWA_NO_WINDOW_CHANGES|_DXGI_MWA_NO_ALT_ENTER); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) resizeSwapChain(width, height int) error {
|
||||
if g.swapChain == nil {
|
||||
return fmt.Errorf("directx: swap chain must be initialized at resizeSwapChain, but is not")
|
||||
}
|
||||
|
||||
var flag uint32
|
||||
if g.allowTearing {
|
||||
flag |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
||||
}
|
||||
if err := g.swapChain.ResizeBuffers(uint32(g.bufferCount), uint32(width), uint32(height), _DXGI_FORMAT_B8G8R8A8_UNORM, flag); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) currentBackBufferIndex() (int, error) {
|
||||
if g.swapChain4 == nil {
|
||||
return 0, fmt.Errorf("directx: IDXGISwapChain4 is not available")
|
||||
}
|
||||
return int(g.swapChain4.GetCurrentBackBufferIndex()), nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) present(vsyncEnabled bool) error {
|
||||
if g.swapChain == nil {
|
||||
return fmt.Errorf("directx: swap chain must be initialized at present, but is not")
|
||||
}
|
||||
|
||||
var syncInterval uint32
|
||||
var flags _DXGI_PRESENT
|
||||
if g.occluded {
|
||||
// The screen is not visible. Test whether we can resume.
|
||||
flags |= _DXGI_PRESENT_TEST
|
||||
} else {
|
||||
// Do actual rendering only when the screen is visible.
|
||||
if vsyncEnabled {
|
||||
syncInterval = 1
|
||||
} else if g.allowTearing {
|
||||
flags |= _DXGI_PRESENT_ALLOW_TEARING
|
||||
}
|
||||
}
|
||||
|
||||
occluded, err := g.swapChain.Present(syncInterval, uint32(flags))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.occluded = occluded
|
||||
|
||||
// Reduce FPS when the screen is invisible.
|
||||
now := time.Now()
|
||||
if g.occluded {
|
||||
if delta := 100*time.Millisecond - now.Sub(g.lastTime); delta > 0 {
|
||||
time.Sleep(delta)
|
||||
}
|
||||
}
|
||||
g.lastTime = now
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphicsInfra) getBuffer(buffer uint32, riid *windows.GUID) (unsafe.Pointer, error) {
|
||||
return g.swapChain.GetBuffer(buffer, riid)
|
||||
}
|
||||
Generated
Vendored
+216
@@ -0,0 +1,216 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
)
|
||||
|
||||
type image11 struct {
|
||||
graphics *graphics11
|
||||
id graphicsdriver.ImageID
|
||||
width int
|
||||
height int
|
||||
screen bool
|
||||
|
||||
texture *_ID3D11Texture2D
|
||||
stencil *_ID3D11Texture2D
|
||||
renderTargetView *_ID3D11RenderTargetView
|
||||
stencilView *_ID3D11DepthStencilView
|
||||
shaderResourceView *_ID3D11ShaderResourceView
|
||||
}
|
||||
|
||||
func (i *image11) internalSize() (int, int) {
|
||||
if i.screen {
|
||||
return i.width, i.height
|
||||
}
|
||||
return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||
}
|
||||
|
||||
func (i *image11) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *image11) Dispose() {
|
||||
i.disposeBuffers()
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *image11) disposeBuffers() {
|
||||
if i.texture != nil {
|
||||
i.texture.Release()
|
||||
i.texture = nil
|
||||
}
|
||||
if i.stencil != nil {
|
||||
i.stencil.Release()
|
||||
i.stencil = nil
|
||||
}
|
||||
if i.renderTargetView != nil {
|
||||
i.renderTargetView.Release()
|
||||
i.renderTargetView = nil
|
||||
}
|
||||
if i.stencilView != nil {
|
||||
i.stencilView.Release()
|
||||
i.stencilView = nil
|
||||
}
|
||||
if i.shaderResourceView != nil {
|
||||
i.shaderResourceView.Release()
|
||||
i.shaderResourceView = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (i *image11) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
var unionRegion image.Rectangle
|
||||
for _, a := range args {
|
||||
unionRegion = unionRegion.Union(a.Region)
|
||||
}
|
||||
|
||||
staging, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(unionRegion.Dx()),
|
||||
Height: uint32(unionRegion.Dy()),
|
||||
MipLevels: 0,
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_STAGING,
|
||||
BindFlags: 0,
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_READ),
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer staging.Release()
|
||||
|
||||
i.graphics.deviceContext.CopySubresourceRegion(unsafe.Pointer(staging), 0, 0, 0, 0, unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||
left: uint32(unionRegion.Min.X),
|
||||
top: uint32(unionRegion.Min.Y),
|
||||
front: 0,
|
||||
right: uint32(unionRegion.Max.X),
|
||||
bottom: uint32(unionRegion.Max.Y),
|
||||
back: 1,
|
||||
})
|
||||
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := i.graphics.deviceContext.Map(unsafe.Pointer(staging), 0, _D3D11_MAP_READ, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stride := int(mapped.RowPitch)
|
||||
srcPix := unsafe.Slice((*byte)(mapped.pData), stride*unionRegion.Dy())
|
||||
for _, a := range args {
|
||||
w := a.Region.Dx()
|
||||
if unionRegion == a.Region && stride == 4*w {
|
||||
copy(a.Pixels, srcPix)
|
||||
continue
|
||||
}
|
||||
offset := 4*(a.Region.Min.X-unionRegion.Min.X) + stride*(a.Region.Min.Y-unionRegion.Min.Y)
|
||||
for j := 0; j < a.Region.Dy(); j++ {
|
||||
copy(a.Pixels[j*4*w:(j+1)*4*w], srcPix[offset+j*stride:])
|
||||
}
|
||||
}
|
||||
|
||||
i.graphics.deviceContext.Unmap(unsafe.Pointer(staging), 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
for _, a := range args {
|
||||
i.graphics.deviceContext.UpdateSubresource(unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||
left: uint32(a.Region.Min.X),
|
||||
top: uint32(a.Region.Min.Y),
|
||||
front: 0,
|
||||
right: uint32(a.Region.Max.X),
|
||||
bottom: uint32(a.Region.Max.Y),
|
||||
back: 1,
|
||||
}, unsafe.Pointer(&a.Pixels[0]), uint32(4*a.Region.Dx()), 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) setAsRenderTarget(useStencil bool) error {
|
||||
if i.renderTargetView == nil {
|
||||
rtv, err := i.graphics.device.CreateRenderTargetView(unsafe.Pointer(i.texture), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.renderTargetView = rtv
|
||||
}
|
||||
|
||||
if !useStencil {
|
||||
i.graphics.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{i.renderTargetView}, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.screen {
|
||||
return fmt.Errorf("directx: a stencil buffer is not available for a screen image")
|
||||
}
|
||||
|
||||
if i.stencil == nil {
|
||||
w, h := i.internalSize()
|
||||
s, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(w),
|
||||
Height: uint32(h),
|
||||
MipLevels: 0,
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_DEFAULT,
|
||||
BindFlags: uint32(_D3D11_BIND_DEPTH_STENCIL),
|
||||
CPUAccessFlags: 0,
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencil = s
|
||||
}
|
||||
|
||||
if i.stencilView == nil {
|
||||
sv, err := i.graphics.device.CreateDepthStencilView(unsafe.Pointer(i.stencil), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencilView = sv
|
||||
}
|
||||
|
||||
i.graphics.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{i.renderTargetView}, i.stencilView)
|
||||
i.graphics.deviceContext.ClearDepthStencilView(i.stencilView, uint8(_D3D11_CLEAR_STENCIL), 0, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) getShaderResourceView() (*_ID3D11ShaderResourceView, error) {
|
||||
if i.shaderResourceView == nil {
|
||||
srv, err := i.graphics.device.CreateShaderResourceView(unsafe.Pointer(i.texture), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.shaderResourceView = srv
|
||||
}
|
||||
return i.shaderResourceView, nil
|
||||
}
|
||||
Generated
Vendored
+426
@@ -0,0 +1,426 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
)
|
||||
|
||||
type image12 struct {
|
||||
graphics *graphics12
|
||||
id graphicsdriver.ImageID
|
||||
width int
|
||||
height int
|
||||
screen bool
|
||||
|
||||
states [frameCount]_D3D12_RESOURCE_STATES
|
||||
texture *_ID3D12Resource
|
||||
stencil *_ID3D12Resource
|
||||
rtvDescriptorHeap *_ID3D12DescriptorHeap
|
||||
dsvDescriptorHeap *_ID3D12DescriptorHeap
|
||||
|
||||
uploadingStagingBuffers []*_ID3D12Resource
|
||||
}
|
||||
|
||||
func (i *image12) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *image12) Dispose() {
|
||||
// Dipose the images later as this image might still be used.
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *image12) disposeImpl() {
|
||||
if i.dsvDescriptorHeap != nil {
|
||||
i.dsvDescriptorHeap.Release()
|
||||
i.dsvDescriptorHeap = nil
|
||||
}
|
||||
if i.rtvDescriptorHeap != nil {
|
||||
i.rtvDescriptorHeap.Release()
|
||||
i.rtvDescriptorHeap = nil
|
||||
}
|
||||
if i.stencil != nil {
|
||||
i.stencil.Release()
|
||||
i.stencil = nil
|
||||
}
|
||||
if i.texture != nil {
|
||||
i.texture.Release()
|
||||
i.texture = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (i *image12) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
if i.screen {
|
||||
return errors.New("directx: Pixels cannot be called on the screen")
|
||||
}
|
||||
|
||||
if err := i.graphics.flushCommandList(i.graphics.drawCommandList); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var unionRegion image.Rectangle
|
||||
for _, a := range args {
|
||||
unionRegion = unionRegion.Union(a.Region)
|
||||
}
|
||||
|
||||
desc := _D3D12_RESOURCE_DESC{
|
||||
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||
Alignment: 0,
|
||||
Width: uint64(unionRegion.Dx()),
|
||||
Height: uint32(unionRegion.Dy()),
|
||||
DepthOrArraySize: 1,
|
||||
MipLevels: 0,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
||||
Flags: _D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
||||
}
|
||||
layouts, _, _, totalBytes := i.graphics.device.GetCopyableFootprints(&desc, 0, 1, 0)
|
||||
readingStagingBuffer, err := createBuffer(i.graphics.device, totalBytes, _D3D12_HEAP_TYPE_READBACK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
readingStagingBuffer.Release()
|
||||
}()
|
||||
|
||||
if rb, ok := i.transiteState(_D3D12_RESOURCE_STATE_COPY_SOURCE); ok {
|
||||
i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb})
|
||||
}
|
||||
|
||||
m, err := readingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dst := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{
|
||||
pResource: readingStagingBuffer,
|
||||
Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
||||
PlacedFootprint: layouts,
|
||||
}
|
||||
src := _D3D12_TEXTURE_COPY_LOCATION_SubresourceIndex{
|
||||
pResource: i.texture,
|
||||
Type: _D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
||||
SubresourceIndex: 0,
|
||||
}
|
||||
i.graphics.needFlushCopyCommandList = true
|
||||
i.graphics.copyCommandList.CopyTextureRegion_PlacedFootPrint_SubresourceIndex(
|
||||
&dst, 0, 0, 0, &src, &_D3D12_BOX{
|
||||
left: uint32(unionRegion.Min.X),
|
||||
top: uint32(unionRegion.Min.Y),
|
||||
front: 0,
|
||||
right: uint32(unionRegion.Max.X),
|
||||
bottom: uint32(unionRegion.Max.Y),
|
||||
back: 1,
|
||||
})
|
||||
|
||||
if err := i.graphics.flushCommandList(i.graphics.copyCommandList); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stride := int(layouts.Footprint.RowPitch)
|
||||
srcPix := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
||||
for _, a := range args {
|
||||
w := a.Region.Dx()
|
||||
if unionRegion == a.Region && stride == 4*w {
|
||||
copy(a.Pixels, srcPix)
|
||||
continue
|
||||
}
|
||||
offset := 4*(a.Region.Min.X-unionRegion.Min.X) + stride*(a.Region.Min.Y-unionRegion.Min.Y)
|
||||
for j := 0; j < a.Region.Dy(); j++ {
|
||||
copy(a.Pixels[j*w*4:(j+1)*w*4], srcPix[offset+j*stride:])
|
||||
}
|
||||
}
|
||||
|
||||
readingStagingBuffer.Unmap(0, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image12) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
if i.screen {
|
||||
return errors.New("directx: WritePixels cannot be called on the screen")
|
||||
}
|
||||
|
||||
if err := i.graphics.flushCommandList(i.graphics.drawCommandList); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var region image.Rectangle
|
||||
for _, a := range args {
|
||||
region = region.Union(a.Region)
|
||||
}
|
||||
|
||||
desc := _D3D12_RESOURCE_DESC{
|
||||
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||
Alignment: 0,
|
||||
Width: uint64(region.Dx()),
|
||||
Height: uint32(region.Dy()),
|
||||
DepthOrArraySize: 1,
|
||||
MipLevels: 0,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
||||
Flags: _D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
||||
}
|
||||
layouts, _, _, totalBytes := i.graphics.device.GetCopyableFootprints(&desc, 0, 1, 0)
|
||||
uploadingStagingBuffer, err := createBuffer(i.graphics.device, totalBytes, _D3D12_HEAP_TYPE_UPLOAD)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.uploadingStagingBuffers = append(i.uploadingStagingBuffers, uploadingStagingBuffer)
|
||||
|
||||
if rb, ok := i.transiteState(_D3D12_RESOURCE_STATE_COPY_DEST); ok {
|
||||
i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb})
|
||||
}
|
||||
|
||||
m, err := uploadingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.graphics.needFlushCopyCommandList = true
|
||||
|
||||
srcBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
||||
for _, a := range args {
|
||||
for j := 0; j < a.Region.Dy(); j++ {
|
||||
copy(srcBytes[((a.Region.Min.Y-region.Min.Y)+j)*int(layouts.Footprint.RowPitch)+(a.Region.Min.X-region.Min.X)*4:], a.Pixels[j*a.Region.Dx()*4:(j+1)*a.Region.Dx()*4])
|
||||
}
|
||||
}
|
||||
|
||||
for _, a := range args {
|
||||
dst := _D3D12_TEXTURE_COPY_LOCATION_SubresourceIndex{
|
||||
pResource: i.texture,
|
||||
Type: _D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
||||
SubresourceIndex: 0,
|
||||
}
|
||||
src := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{
|
||||
pResource: uploadingStagingBuffer,
|
||||
Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
||||
PlacedFootprint: layouts,
|
||||
}
|
||||
i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint(
|
||||
&dst, uint32(a.Region.Min.X), uint32(a.Region.Min.Y), 0, &src, &_D3D12_BOX{
|
||||
left: uint32(a.Region.Min.X - region.Min.X),
|
||||
top: uint32(a.Region.Min.Y - region.Min.Y),
|
||||
front: 0,
|
||||
right: uint32(a.Region.Max.X - region.Min.X),
|
||||
bottom: uint32(a.Region.Max.Y - region.Min.Y),
|
||||
back: 1,
|
||||
})
|
||||
}
|
||||
|
||||
uploadingStagingBuffer.Unmap(0, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image12) resource() *_ID3D12Resource {
|
||||
if i.screen {
|
||||
return i.graphics.renderTargets[i.graphics.frameIndex]
|
||||
}
|
||||
return i.texture
|
||||
}
|
||||
|
||||
func (i *image12) state() _D3D12_RESOURCE_STATES {
|
||||
if i.screen {
|
||||
return i.states[i.graphics.frameIndex]
|
||||
}
|
||||
return i.states[0]
|
||||
}
|
||||
|
||||
func (i *image12) setState(newState _D3D12_RESOURCE_STATES) {
|
||||
if i.screen {
|
||||
i.states[i.graphics.frameIndex] = newState
|
||||
return
|
||||
}
|
||||
i.states[0] = newState
|
||||
}
|
||||
|
||||
func (i *image12) transiteState(newState _D3D12_RESOURCE_STATES) (_D3D12_RESOURCE_BARRIER_Transition, bool) {
|
||||
if i.state() == newState {
|
||||
return _D3D12_RESOURCE_BARRIER_Transition{}, false
|
||||
}
|
||||
oldState := i.state()
|
||||
i.setState(newState)
|
||||
|
||||
return _D3D12_RESOURCE_BARRIER_Transition{
|
||||
Type: _D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
Flags: _D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
Transition: _D3D12_RESOURCE_TRANSITION_BARRIER{
|
||||
pResource: i.resource(),
|
||||
Subresource: _D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
|
||||
StateBefore: oldState,
|
||||
StateAfter: newState,
|
||||
},
|
||||
}, true
|
||||
}
|
||||
|
||||
func (i *image12) internalSize() (int, int) {
|
||||
if i.screen {
|
||||
return i.width, i.height
|
||||
}
|
||||
return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||
}
|
||||
|
||||
func (i *image12) setAsRenderTarget(drawCommandList *_ID3D12GraphicsCommandList, device *_ID3D12Device, useStencil bool) error {
|
||||
if err := i.ensureRenderTargetView(device); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i.screen {
|
||||
if useStencil {
|
||||
return fmt.Errorf("directx: stencils are not available on the screen framebuffer")
|
||||
}
|
||||
rtv, err := i.graphics.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rtv.Offset(int32(i.graphics.frameIndex), i.graphics.rtvDescriptorSize)
|
||||
drawCommandList.OMSetRenderTargets([]_D3D12_CPU_DESCRIPTOR_HANDLE{rtv}, false, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
rtv, err := i.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !useStencil {
|
||||
drawCommandList.OMSetRenderTargets([]_D3D12_CPU_DESCRIPTOR_HANDLE{rtv}, false, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := i.ensureDepthStencilView(device); err != nil {
|
||||
return err
|
||||
}
|
||||
dsv, err := i.dsvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
drawCommandList.OMSetStencilRef(0)
|
||||
drawCommandList.OMSetRenderTargets([]_D3D12_CPU_DESCRIPTOR_HANDLE{rtv}, false, &dsv)
|
||||
drawCommandList.ClearDepthStencilView(dsv, _D3D12_CLEAR_FLAG_STENCIL, 0, 0, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image12) ensureRenderTargetView(device *_ID3D12Device) error {
|
||||
if i.screen {
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.rtvDescriptorHeap != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
h, err := device.CreateDescriptorHeap(&_D3D12_DESCRIPTOR_HEAP_DESC{
|
||||
Type: _D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
|
||||
NumDescriptors: 1,
|
||||
Flags: _D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
|
||||
NodeMask: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.rtvDescriptorHeap = h
|
||||
|
||||
rtv, err := i.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
device.CreateRenderTargetView(i.texture, nil, rtv)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image12) ensureDepthStencilView(device *_ID3D12Device) error {
|
||||
if i.screen {
|
||||
return fmt.Errorf("directx: stencils are not available on the screen framebuffer")
|
||||
}
|
||||
|
||||
if i.dsvDescriptorHeap != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
h, err := device.CreateDescriptorHeap(&_D3D12_DESCRIPTOR_HEAP_DESC{
|
||||
Type: _D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
|
||||
NumDescriptors: 1,
|
||||
Flags: _D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
|
||||
NodeMask: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.dsvDescriptorHeap = h
|
||||
|
||||
dsv, err := i.dsvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i.stencil == nil {
|
||||
s, err := device.CreateCommittedResource(&_D3D12_HEAP_PROPERTIES{
|
||||
Type: _D3D12_HEAP_TYPE_DEFAULT,
|
||||
CPUPageProperty: _D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
MemoryPoolPreference: _D3D12_MEMORY_POOL_UNKNOWN,
|
||||
CreationNodeMask: 1,
|
||||
VisibleNodeMask: 1,
|
||||
}, _D3D12_HEAP_FLAG_NONE, &_D3D12_RESOURCE_DESC{
|
||||
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||
Alignment: 0,
|
||||
Width: uint64(graphics.InternalImageSize(i.width)),
|
||||
Height: uint32(graphics.InternalImageSize(i.height)),
|
||||
DepthOrArraySize: 1,
|
||||
MipLevels: 0,
|
||||
Format: _DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
||||
Flags: _D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL,
|
||||
}, _D3D12_RESOURCE_STATE_DEPTH_WRITE, &_D3D12_CLEAR_VALUE{
|
||||
Format: _DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencil = s
|
||||
}
|
||||
device.CreateDepthStencilView(i.stencil, nil, dsv)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image12) releaseUploadingStagingBuffers() {
|
||||
for idx, buf := range i.uploadingStagingBuffers {
|
||||
buf.Release()
|
||||
i.uploadingStagingBuffers[idx] = nil
|
||||
}
|
||||
i.uploadingStagingBuffers = i.uploadingStagingBuffers[:0]
|
||||
}
|
||||
Generated
Vendored
+567
@@ -0,0 +1,567 @@
|
||||
// Copyright 2022 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"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,
|
||||
},
|
||||
}
|
||||
|
||||
const numDescriptorsPerFrame = 32
|
||||
|
||||
func blendFactorToBlend12(f graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND {
|
||||
// D3D12_RENDER_TARGET_BLEND_DESC's *BlendAlpha members don't allow *_COLOR values.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc.
|
||||
|
||||
switch f {
|
||||
case graphicsdriver.BlendFactorZero:
|
||||
return _D3D12_BLEND_ZERO
|
||||
case graphicsdriver.BlendFactorOne:
|
||||
return _D3D12_BLEND_ONE
|
||||
case graphicsdriver.BlendFactorSourceColor:
|
||||
if alpha {
|
||||
return _D3D12_BLEND_SRC_ALPHA
|
||||
}
|
||||
return _D3D12_BLEND_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusSourceColor:
|
||||
if alpha {
|
||||
return _D3D12_BLEND_INV_SRC_ALPHA
|
||||
}
|
||||
return _D3D12_BLEND_INV_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorSourceAlpha:
|
||||
return _D3D12_BLEND_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusSourceAlpha:
|
||||
return _D3D12_BLEND_INV_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorDestinationColor:
|
||||
if alpha {
|
||||
return _D3D12_BLEND_DEST_ALPHA
|
||||
}
|
||||
return _D3D12_BLEND_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationColor:
|
||||
if alpha {
|
||||
return _D3D12_BLEND_INV_DEST_ALPHA
|
||||
}
|
||||
return _D3D12_BLEND_INV_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorDestinationAlpha:
|
||||
return _D3D12_BLEND_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationAlpha:
|
||||
return _D3D12_BLEND_INV_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorSourceAlphaSaturated:
|
||||
return _D3D12_BLEND_SRC_ALPHA_SAT
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend factor: %d", f))
|
||||
}
|
||||
}
|
||||
|
||||
func blendOperationToBlendOp12(o graphicsdriver.BlendOperation) _D3D12_BLEND_OP {
|
||||
switch o {
|
||||
case graphicsdriver.BlendOperationAdd:
|
||||
return _D3D12_BLEND_OP_ADD
|
||||
case graphicsdriver.BlendOperationSubtract:
|
||||
return _D3D12_BLEND_OP_SUBTRACT
|
||||
case graphicsdriver.BlendOperationReverseSubtract:
|
||||
return _D3D12_BLEND_OP_REV_SUBTRACT
|
||||
case graphicsdriver.BlendOperationMin:
|
||||
return _D3D12_BLEND_OP_MIN
|
||||
case graphicsdriver.BlendOperationMax:
|
||||
return _D3D12_BLEND_OP_MAX
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend operation: %d", o))
|
||||
}
|
||||
}
|
||||
|
||||
type pipelineStates struct {
|
||||
rootSignature *_ID3D12RootSignature
|
||||
|
||||
shaderDescriptorHeap *_ID3D12DescriptorHeap
|
||||
shaderDescriptorSize uint32
|
||||
|
||||
samplerDescriptorHeap *_ID3D12DescriptorHeap
|
||||
|
||||
constantBuffers [frameCount][]*_ID3D12Resource
|
||||
constantBufferMaps [frameCount][]uintptr
|
||||
}
|
||||
|
||||
const numConstantBufferAndSourceTextures = 1 + graphics.ShaderImageCount
|
||||
|
||||
func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
||||
// Create a CBV/SRV/UAV descriptor heap.
|
||||
// 5n+0: constants
|
||||
// 5n+m (1<=4): textures
|
||||
shaderH, err := device.CreateDescriptorHeap(&_D3D12_DESCRIPTOR_HEAP_DESC{
|
||||
Type: _D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
NumDescriptors: frameCount * numDescriptorsPerFrame * numConstantBufferAndSourceTextures,
|
||||
Flags: _D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
|
||||
NodeMask: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.shaderDescriptorHeap = shaderH
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
p.shaderDescriptorHeap.Release()
|
||||
p.shaderDescriptorHeap = nil
|
||||
}
|
||||
}()
|
||||
p.shaderDescriptorSize = device.GetDescriptorHandleIncrementSize(_D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
|
||||
|
||||
samplerH, err := device.CreateDescriptorHeap(&_D3D12_DESCRIPTOR_HEAP_DESC{
|
||||
Type: _D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
NumDescriptors: 1,
|
||||
Flags: _D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
|
||||
NodeMask: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.samplerDescriptorHeap = samplerH
|
||||
|
||||
h, err := p.samplerDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
device.CreateSampler(&_D3D12_SAMPLER_DESC{
|
||||
Filter: _D3D12_FILTER_MIN_MAG_MIP_POINT,
|
||||
AddressU: _D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
AddressV: _D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
AddressW: _D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
ComparisonFunc: _D3D12_COMPARISON_FUNC_NEVER,
|
||||
MinLOD: -math.MaxFloat32,
|
||||
MaxLOD: math.MaxFloat32,
|
||||
}, h)
|
||||
|
||||
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 {
|
||||
idx := len(p.constantBuffers[frameIndex])
|
||||
if idx >= numDescriptorsPerFrame {
|
||||
return fmt.Errorf("directx: too many constant buffers")
|
||||
}
|
||||
|
||||
if cap(p.constantBuffers[frameIndex]) > idx {
|
||||
p.constantBuffers[frameIndex] = p.constantBuffers[frameIndex][:idx+1]
|
||||
p.constantBufferMaps[frameIndex] = p.constantBufferMaps[frameIndex][:idx+1]
|
||||
} else {
|
||||
p.constantBuffers[frameIndex] = append(p.constantBuffers[frameIndex], nil)
|
||||
p.constantBufferMaps[frameIndex] = append(p.constantBufferMaps[frameIndex], 0)
|
||||
}
|
||||
|
||||
const bufferSizeAlignment = 256
|
||||
bufferSize := uint32(unsafe.Sizeof(uint32(0))) * uint32(len(uniforms))
|
||||
if bufferSize > 0 {
|
||||
bufferSize = ((bufferSize-1)/bufferSizeAlignment + 1) * bufferSizeAlignment
|
||||
}
|
||||
|
||||
cb := p.constantBuffers[frameIndex][idx]
|
||||
m := p.constantBufferMaps[frameIndex][idx]
|
||||
if cb != nil {
|
||||
if uint32(cb.GetDesc().Width) < bufferSize {
|
||||
p.constantBuffers[frameIndex][idx].Unmap(0, nil)
|
||||
p.constantBuffers[frameIndex][idx].Release()
|
||||
p.constantBuffers[frameIndex][idx] = nil
|
||||
p.constantBufferMaps[frameIndex][idx] = 0
|
||||
cb = nil
|
||||
}
|
||||
}
|
||||
if cb == nil {
|
||||
var err error
|
||||
cb, err = createBuffer(device, uint64(bufferSize), _D3D12_HEAP_TYPE_UPLOAD)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.constantBuffers[frameIndex][idx] = cb
|
||||
|
||||
h, err := p.shaderDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offset := int32(numConstantBufferAndSourceTextures * (frameIndex*numDescriptorsPerFrame + idx))
|
||||
h.Offset(offset, p.shaderDescriptorSize)
|
||||
device.CreateConstantBufferView(&_D3D12_CONSTANT_BUFFER_VIEW_DESC{
|
||||
BufferLocation: cb.GetGPUVirtualAddress(),
|
||||
SizeInBytes: bufferSize,
|
||||
}, h)
|
||||
|
||||
m, err = cb.Map(0, &_D3D12_RANGE{0, 0})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.constantBufferMaps[frameIndex][idx] = m
|
||||
}
|
||||
if m == 0 {
|
||||
return fmt.Errorf("directx: ID3D12Resource::Map failed")
|
||||
}
|
||||
|
||||
h, err := p.shaderDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offset := int32(numConstantBufferAndSourceTextures * (frameIndex*numDescriptorsPerFrame + idx))
|
||||
h.Offset(offset, p.shaderDescriptorSize)
|
||||
for _, src := range srcs {
|
||||
h.Offset(1, p.shaderDescriptorSize)
|
||||
if src == nil {
|
||||
continue
|
||||
}
|
||||
device.CreateShaderResourceView(src.resource(), &_D3D12_SHADER_RESOURCE_VIEW_DESC{
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
ViewDimension: _D3D12_SRV_DIMENSION_TEXTURE2D,
|
||||
Shader4ComponentMapping: _D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
||||
Texture2D: _D3D12_TEX2D_SRV{
|
||||
MipLevels: 1, // TODO: Can this be 0?
|
||||
},
|
||||
}, h)
|
||||
}
|
||||
|
||||
// Update the constant buffer.
|
||||
copy(unsafe.Slice((*uint32)(unsafe.Pointer(m)), len(uniforms)), uniforms)
|
||||
|
||||
rs, err := p.ensureRootSignature(device)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetGraphicsRootSignature(rs)
|
||||
|
||||
commandList.SetDescriptorHeaps([]*_ID3D12DescriptorHeap{
|
||||
p.shaderDescriptorHeap,
|
||||
p.samplerDescriptorHeap,
|
||||
})
|
||||
|
||||
// Match the indices with rootParams in graphicsPipelineState.
|
||||
gh, err := p.shaderDescriptorHeap.GetGPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gh.Offset(offset, p.shaderDescriptorSize)
|
||||
commandList.SetGraphicsRootDescriptorTable(0, gh)
|
||||
commandList.SetGraphicsRootDescriptorTable(1, gh)
|
||||
sh, err := p.samplerDescriptorHeap.GetGPUDescriptorHandleForHeapStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetGraphicsRootDescriptorTable(2, sh)
|
||||
|
||||
if fillRule == graphicsdriver.FillAll {
|
||||
s, err := shader.pipelineState(blend, noStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
}
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
commandList.RSSetScissorRects([]_D3D12_RECT{
|
||||
{
|
||||
left: int32(dstRegion.Region.Min.X),
|
||||
top: int32(dstRegion.Region.Min.Y),
|
||||
right: int32(dstRegion.Region.Max.X),
|
||||
bottom: int32(dstRegion.Region.Max.Y),
|
||||
},
|
||||
})
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
case graphicsdriver.NonZero:
|
||||
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:
|
||||
s, err := shader.pipelineState(blend, invertStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
s, err := shader.pipelineState(blend, drawWithStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
}
|
||||
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipelineStates) ensureRootSignature(device *_ID3D12Device) (rootSignature *_ID3D12RootSignature, ferr error) {
|
||||
if p.rootSignature != nil {
|
||||
return p.rootSignature, nil
|
||||
}
|
||||
|
||||
cbv := _D3D12_DESCRIPTOR_RANGE{
|
||||
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_CBV, // b0
|
||||
NumDescriptors: 1,
|
||||
BaseShaderRegister: 0,
|
||||
RegisterSpace: 0,
|
||||
OffsetInDescriptorsFromTableStart: 0,
|
||||
}
|
||||
srv := _D3D12_DESCRIPTOR_RANGE{
|
||||
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // t0
|
||||
NumDescriptors: graphics.ShaderImageCount,
|
||||
BaseShaderRegister: 0,
|
||||
RegisterSpace: 0,
|
||||
OffsetInDescriptorsFromTableStart: 1,
|
||||
}
|
||||
sampler := _D3D12_DESCRIPTOR_RANGE{
|
||||
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, // s0
|
||||
NumDescriptors: 1,
|
||||
BaseShaderRegister: 0,
|
||||
RegisterSpace: 0,
|
||||
OffsetInDescriptorsFromTableStart: 0,
|
||||
}
|
||||
|
||||
rootParams := [...]_D3D12_ROOT_PARAMETER{
|
||||
{
|
||||
ParameterType: _D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
DescriptorTable: _D3D12_ROOT_DESCRIPTOR_TABLE{
|
||||
NumDescriptorRanges: 1,
|
||||
pDescriptorRanges: &cbv,
|
||||
},
|
||||
ShaderVisibility: _D3D12_SHADER_VISIBILITY_ALL,
|
||||
},
|
||||
{
|
||||
ParameterType: _D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
DescriptorTable: _D3D12_ROOT_DESCRIPTOR_TABLE{
|
||||
NumDescriptorRanges: 1,
|
||||
pDescriptorRanges: &srv,
|
||||
},
|
||||
ShaderVisibility: _D3D12_SHADER_VISIBILITY_PIXEL,
|
||||
},
|
||||
{
|
||||
ParameterType: _D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
DescriptorTable: _D3D12_ROOT_DESCRIPTOR_TABLE{
|
||||
NumDescriptorRanges: 1,
|
||||
pDescriptorRanges: &sampler,
|
||||
},
|
||||
ShaderVisibility: _D3D12_SHADER_VISIBILITY_PIXEL,
|
||||
},
|
||||
}
|
||||
|
||||
// Create a root signature.
|
||||
sig, err := _D3D12SerializeRootSignature(&_D3D12_ROOT_SIGNATURE_DESC{
|
||||
NumParameters: uint32(len(rootParams)),
|
||||
pParameters: &rootParams[0],
|
||||
NumStaticSamplers: 0,
|
||||
pStaticSamplers: nil,
|
||||
Flags: _D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT,
|
||||
}, _D3D_ROOT_SIGNATURE_VERSION_1_0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sig.Release()
|
||||
|
||||
rs, err := device.CreateRootSignature(0, sig.GetBufferPointer(), sig.GetBufferSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
rootSignature.Release()
|
||||
}
|
||||
}()
|
||||
|
||||
p.rootSignature = rs
|
||||
|
||||
return p.rootSignature, nil
|
||||
}
|
||||
|
||||
func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3DBlob, blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (state *_ID3D12PipelineState, ferr error) {
|
||||
rootSignature, err := p.ensureRootSignature(device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if ferr != nil {
|
||||
rootSignature.Release()
|
||||
}
|
||||
}()
|
||||
|
||||
depthStencilDesc := _D3D12_DEPTH_STENCIL_DESC{
|
||||
DepthEnable: 0,
|
||||
DepthWriteMask: _D3D12_DEPTH_WRITE_MASK_ALL,
|
||||
DepthFunc: _D3D12_COMPARISON_FUNC_LESS,
|
||||
StencilEnable: 0,
|
||||
StencilReadMask: _D3D12_DEFAULT_STENCIL_READ_MASK,
|
||||
StencilWriteMask: _D3D12_DEFAULT_STENCIL_WRITE_MASK,
|
||||
FrontFace: _D3D12_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D12_COMPARISON_FUNC_ALWAYS,
|
||||
},
|
||||
BackFace: _D3D12_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D12_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D12_COMPARISON_FUNC_ALWAYS,
|
||||
},
|
||||
}
|
||||
|
||||
var writeMask uint8
|
||||
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||
writeMask = uint8(_D3D12_COLOR_WRITE_ENABLE_ALL)
|
||||
}
|
||||
|
||||
switch stencilMode {
|
||||
case incrementStencil:
|
||||
depthStencilDesc.StencilEnable = 1
|
||||
depthStencilDesc.FrontFace.StencilPassOp = _D3D12_STENCIL_OP_INCR
|
||||
depthStencilDesc.BackFace.StencilPassOp = _D3D12_STENCIL_OP_DECR
|
||||
case invertStencil:
|
||||
depthStencilDesc.StencilEnable = 1
|
||||
depthStencilDesc.FrontFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
||||
depthStencilDesc.BackFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
||||
case drawWithStencil:
|
||||
depthStencilDesc.StencilEnable = 1
|
||||
depthStencilDesc.FrontFace.StencilFunc = _D3D12_COMPARISON_FUNC_NOT_EQUAL
|
||||
depthStencilDesc.BackFace.StencilFunc = _D3D12_COMPARISON_FUNC_NOT_EQUAL
|
||||
}
|
||||
|
||||
rtvFormat := _DXGI_FORMAT_R8G8B8A8_UNORM
|
||||
if screen {
|
||||
rtvFormat = _DXGI_FORMAT_B8G8R8A8_UNORM
|
||||
}
|
||||
dsvFormat := _DXGI_FORMAT_UNKNOWN
|
||||
if stencilMode != noStencil {
|
||||
dsvFormat = _DXGI_FORMAT_D24_UNORM_S8_UINT
|
||||
}
|
||||
|
||||
// Create a pipeline state.
|
||||
psoDesc := _D3D12_GRAPHICS_PIPELINE_STATE_DESC{
|
||||
pRootSignature: rootSignature,
|
||||
VS: _D3D12_SHADER_BYTECODE{
|
||||
pShaderBytecode: vsh.GetBufferPointer(),
|
||||
BytecodeLength: vsh.GetBufferSize(),
|
||||
},
|
||||
PS: _D3D12_SHADER_BYTECODE{
|
||||
pShaderBytecode: psh.GetBufferPointer(),
|
||||
BytecodeLength: psh.GetBufferSize(),
|
||||
},
|
||||
BlendState: _D3D12_BLEND_DESC{
|
||||
AlphaToCoverageEnable: 0,
|
||||
IndependentBlendEnable: 0,
|
||||
RenderTarget: [8]_D3D12_RENDER_TARGET_BLEND_DESC{
|
||||
{
|
||||
BlendEnable: 1,
|
||||
LogicOpEnable: 0,
|
||||
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
|
||||
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
|
||||
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
|
||||
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
|
||||
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
|
||||
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
|
||||
LogicOp: _D3D12_LOGIC_OP_NOOP,
|
||||
RenderTargetWriteMask: writeMask,
|
||||
},
|
||||
},
|
||||
},
|
||||
SampleMask: math.MaxUint32,
|
||||
RasterizerState: _D3D12_RASTERIZER_DESC{
|
||||
FillMode: _D3D12_FILL_MODE_SOLID,
|
||||
CullMode: _D3D12_CULL_MODE_NONE,
|
||||
FrontCounterClockwise: 0,
|
||||
DepthBias: _D3D12_DEFAULT_DEPTH_BIAS,
|
||||
DepthBiasClamp: _D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
|
||||
SlopeScaledDepthBias: _D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
|
||||
DepthClipEnable: 0,
|
||||
MultisampleEnable: 0,
|
||||
AntialiasedLineEnable: 0,
|
||||
ForcedSampleCount: 0,
|
||||
ConservativeRaster: _D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
|
||||
},
|
||||
DepthStencilState: depthStencilDesc,
|
||||
InputLayout: _D3D12_INPUT_LAYOUT_DESC{
|
||||
pInputElementDescs: &inputElementDescsForDX12[0],
|
||||
NumElements: uint32(len(inputElementDescsForDX12)),
|
||||
},
|
||||
PrimitiveTopologyType: _D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
|
||||
NumRenderTargets: 1,
|
||||
RTVFormats: [8]_DXGI_FORMAT{
|
||||
rtvFormat,
|
||||
},
|
||||
DSVFormat: dsvFormat,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
}
|
||||
|
||||
s, err := device.CreateGraphicsPipelineState(&psoDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (p *pipelineStates) releaseConstantBuffers(frameIndex int) {
|
||||
for i := range p.constantBuffers[frameIndex] {
|
||||
p.constantBuffers[frameIndex][i].Unmap(0, nil)
|
||||
p.constantBuffers[frameIndex][i].Release()
|
||||
p.constantBuffers[frameIndex][i] = nil
|
||||
p.constantBufferMaps[frameIndex][i] = 0
|
||||
}
|
||||
p.constantBuffers[frameIndex] = p.constantBuffers[frameIndex][:0]
|
||||
p.constantBufferMaps[frameIndex] = p.constantBufferMaps[frameIndex][:0]
|
||||
}
|
||||
|
||||
func (p *pipelineStates) resetConstantBuffers(frameIndex int) {
|
||||
p.constantBuffers[frameIndex] = p.constantBuffers[frameIndex][:0]
|
||||
p.constantBufferMaps[frameIndex] = p.constantBufferMaps[frameIndex][:0]
|
||||
}
|
||||
Generated
Vendored
+195
@@ -0,0 +1,195 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type shader11 struct {
|
||||
graphics *graphics11
|
||||
id graphicsdriver.ShaderID
|
||||
uniformTypes []shaderir.Type
|
||||
uniformOffsets []int
|
||||
vertexShaderBlob *_ID3DBlob
|
||||
pixelShaderBlob *_ID3DBlob
|
||||
|
||||
inputLayout *_ID3D11InputLayout
|
||||
vertexShader *_ID3D11VertexShader
|
||||
pixelShader *_ID3D11PixelShader
|
||||
constantBuffer *_ID3D11Buffer
|
||||
}
|
||||
|
||||
func (s *shader11) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *shader11) Dispose() {
|
||||
s.graphics.removeShader(s)
|
||||
}
|
||||
|
||||
func (s *shader11) disposeImpl() {
|
||||
if s.pixelShaderBlob != nil {
|
||||
s.pixelShaderBlob.Release()
|
||||
s.pixelShaderBlob = nil
|
||||
}
|
||||
if s.vertexShaderBlob != nil {
|
||||
count := s.vertexShaderBlob.Release()
|
||||
if count == 0 {
|
||||
for k, v := range vertexShaderCache {
|
||||
if v == s.vertexShaderBlob {
|
||||
delete(vertexShaderCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.vertexShader = nil
|
||||
}
|
||||
if s.inputLayout != nil {
|
||||
s.inputLayout.Release()
|
||||
s.inputLayout = nil
|
||||
}
|
||||
if s.vertexShader != nil {
|
||||
s.vertexShader.Release()
|
||||
s.vertexShader = nil
|
||||
}
|
||||
if s.pixelShader != nil {
|
||||
s.pixelShader.Release()
|
||||
s.pixelShader = nil
|
||||
}
|
||||
if s.constantBuffer != nil {
|
||||
s.constantBuffer.Release()
|
||||
s.constantBuffer = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image11) error {
|
||||
vs, err := s.ensureVertexShader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.VSSetShader(vs, nil)
|
||||
|
||||
ps, err := s.ensurePixelShader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.PSSetShader(ps, nil)
|
||||
|
||||
il, err := s.ensureInputLayout()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.IASetInputLayout(il)
|
||||
|
||||
cb, err := s.ensureConstantBuffer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.VSSetConstantBuffers(0, []*_ID3D11Buffer{cb})
|
||||
s.graphics.deviceContext.PSSetConstantBuffers(0, []*_ID3D11Buffer{cb})
|
||||
|
||||
// Send the constant buffer data.
|
||||
uniforms = adjustUniforms(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)
|
||||
s.graphics.deviceContext.Unmap(unsafe.Pointer(cb), 0)
|
||||
|
||||
// Set the render sources.
|
||||
var srvs [graphics.ShaderImageCount]*_ID3D11ShaderResourceView
|
||||
for i, src := range srcs {
|
||||
if src == nil {
|
||||
continue
|
||||
}
|
||||
srv, err := src.getShaderResourceView()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srvs[i] = srv
|
||||
}
|
||||
s.graphics.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensureInputLayout() (*_ID3D11InputLayout, error) {
|
||||
if s.inputLayout != nil {
|
||||
return s.inputLayout, nil
|
||||
}
|
||||
|
||||
i, err := s.graphics.device.CreateInputLayout(inputElementDescsForDX11, s.vertexShaderBlob.GetBufferPointer(), s.vertexShaderBlob.GetBufferSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.inputLayout = i
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensureVertexShader() (*_ID3D11VertexShader, error) {
|
||||
if s.vertexShader != nil {
|
||||
return s.vertexShader, nil
|
||||
}
|
||||
|
||||
vs, err := s.graphics.device.CreateVertexShader(s.vertexShaderBlob.GetBufferPointer(), s.vertexShaderBlob.GetBufferSize(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.vertexShader = vs
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensurePixelShader() (*_ID3D11PixelShader, error) {
|
||||
if s.pixelShader != nil {
|
||||
return s.pixelShader, nil
|
||||
}
|
||||
|
||||
ps, err := s.graphics.device.CreatePixelShader(s.pixelShaderBlob.GetBufferPointer(), s.pixelShaderBlob.GetBufferSize(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.pixelShader = ps
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func alignUp16(x uint32) uint32 {
|
||||
if x%16 == 0 {
|
||||
return x
|
||||
}
|
||||
return x + 16 - (x % 16)
|
||||
}
|
||||
|
||||
func (s *shader11) ensureConstantBuffer() (*_ID3D11Buffer, error) {
|
||||
if s.constantBuffer != nil {
|
||||
return s.constantBuffer, nil
|
||||
}
|
||||
|
||||
cb, err := s.graphics.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: alignUp16(uint32(constantBufferSize(s.uniformTypes, s.uniformOffsets)) * 4),
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_CONSTANT_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.constantBuffer = cb
|
||||
return cb, nil
|
||||
}
|
||||
Generated
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type pipelineStateKey struct {
|
||||
blend graphicsdriver.Blend
|
||||
stencilMode stencilMode
|
||||
screen bool
|
||||
}
|
||||
|
||||
type shader12 struct {
|
||||
graphics *graphics12
|
||||
id graphicsdriver.ShaderID
|
||||
uniformTypes []shaderir.Type
|
||||
uniformOffsets []int
|
||||
vertexShader *_ID3DBlob
|
||||
pixelShader *_ID3DBlob
|
||||
|
||||
pipelineStates map[pipelineStateKey]*_ID3D12PipelineState
|
||||
}
|
||||
|
||||
func (s *shader12) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *shader12) Dispose() {
|
||||
s.graphics.removeShader(s)
|
||||
}
|
||||
|
||||
func (s *shader12) disposeImpl() {
|
||||
for c, p := range s.pipelineStates {
|
||||
p.Release()
|
||||
delete(s.pipelineStates, c)
|
||||
}
|
||||
|
||||
if s.pixelShader != nil {
|
||||
s.pixelShader.Release()
|
||||
s.pixelShader = nil
|
||||
}
|
||||
if s.vertexShader != nil {
|
||||
count := s.vertexShader.Release()
|
||||
if count == 0 {
|
||||
for k, v := range vertexShaderCache {
|
||||
if v == s.vertexShader {
|
||||
delete(vertexShaderCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.vertexShader = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shader12) pipelineState(blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (*_ID3D12PipelineState, error) {
|
||||
key := pipelineStateKey{
|
||||
blend: blend,
|
||||
stencilMode: stencilMode,
|
||||
screen: screen,
|
||||
}
|
||||
if state, ok := s.pipelineStates[key]; ok {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
state, err := s.graphics.pipelineStates.newPipelineState(s.graphics.device, s.vertexShader, s.pixelShader, blend, stencilMode, screen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.pipelineStates == nil {
|
||||
s.pipelineStates = map[pipelineStateKey]*_ID3D12PipelineState{}
|
||||
}
|
||||
s.pipelineStates[key] = state
|
||||
return state, nil
|
||||
}
|
||||
Generated
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
// Copyright 2023 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 directx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
var vertexShaderCache = map[string]*_ID3DBlob{}
|
||||
|
||||
func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
var flag uint32 = uint32(_D3DCOMPILE_OPTIMIZATION_LEVEL3)
|
||||
|
||||
defer func() {
|
||||
if ferr == nil {
|
||||
return
|
||||
}
|
||||
if vsh != nil {
|
||||
vsh.Release()
|
||||
}
|
||||
if psh != nil {
|
||||
psh.Release()
|
||||
}
|
||||
}()
|
||||
|
||||
var wg errgroup.Group
|
||||
|
||||
// Vertex shaders are likely the same. If so, reuse the same _ID3DBlob.
|
||||
if v, ok := vertexShaderCache[vs]; ok {
|
||||
// Increment the reference count not to release this object unexpectedly.
|
||||
// The value will be removed when the count reached 0.
|
||||
// See (*Shader).disposeImpl.
|
||||
v.AddRef()
|
||||
vsh = v
|
||||
} else {
|
||||
defer func() {
|
||||
if ferr == nil {
|
||||
vertexShaderCache[vs] = vsh
|
||||
}
|
||||
}()
|
||||
wg.Go(func() error {
|
||||
v, err := _D3DCompile([]byte(vs), "shader", nil, nil, "VSMain", "vs_4_0", flag, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("directx: D3DCompile for VSMain failed, original source: %s, %w", vs, err)
|
||||
}
|
||||
vsh = v
|
||||
return nil
|
||||
})
|
||||
}
|
||||
wg.Go(func() error {
|
||||
p, err := _D3DCompile([]byte(ps), "shader", nil, nil, "PSMain", "ps_4_0", flag, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("directx: D3DCompile for PSMain failed, original source: %s, %w", ps, err)
|
||||
}
|
||||
psh = p
|
||||
return nil
|
||||
})
|
||||
|
||||
if err := wg.Wait(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
switch typ.Main {
|
||||
case shaderir.Float:
|
||||
size += 1
|
||||
case shaderir.Int:
|
||||
size += 1
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
size += 2
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
size += 3
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
size += 4
|
||||
case shaderir.Mat2:
|
||||
size += 6
|
||||
case shaderir.Mat3:
|
||||
size += 11
|
||||
case shaderir.Mat4:
|
||||
size += 16
|
||||
case shaderir.Array:
|
||||
// Each element is aligned to the boundary.
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Float:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Int:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
size += 4*(typ.Length-1) + 2
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
size += 4*(typ.Length-1) + 3
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
size += 4 * typ.Length
|
||||
case shaderir.Mat2:
|
||||
size += 8*(typ.Length-1) + 6
|
||||
case shaderir.Mat3:
|
||||
size += 12*(typ.Length-1) + 11
|
||||
case shaderir.Mat4:
|
||||
size += 16 * typ.Length
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms []uint32) []uint32 {
|
||||
var fs []uint32
|
||||
var idx int
|
||||
for i, typ := range uniformTypes {
|
||||
if len(fs) < uniformOffsets[i]/4 {
|
||||
fs = append(fs, make([]uint32, uniformOffsets[i]/4-len(fs))...)
|
||||
}
|
||||
|
||||
n := typ.Uint32Count()
|
||||
switch typ.Main {
|
||||
case shaderir.Float:
|
||||
fs = append(fs, uniforms[idx:idx+1]...)
|
||||
case shaderir.Int:
|
||||
fs = append(fs, uniforms[idx:idx+1]...)
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
fs = append(fs, uniforms[idx:idx+2]...)
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
fs = append(fs, uniforms[idx:idx+3]...)
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
fs = append(fs, uniforms[idx:idx+4]...)
|
||||
case shaderir.Mat2:
|
||||
fs = append(fs,
|
||||
uniforms[idx+0], uniforms[idx+2], 0, 0,
|
||||
uniforms[idx+1], uniforms[idx+3],
|
||||
)
|
||||
case shaderir.Mat3:
|
||||
fs = append(fs,
|
||||
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],
|
||||
)
|
||||
case shaderir.Mat4:
|
||||
if i == graphics.ProjectionMatrixUniformVariableIndex {
|
||||
// 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,
|
||||
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,
|
||||
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],
|
||||
uniforms[idx+3], uniforms[idx+7], uniforms[idx+11], uniforms[idx+15],
|
||||
)
|
||||
}
|
||||
case shaderir.Array:
|
||||
// Each element is aligned to the boundary.
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Float:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+j])
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Int:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
fs = append(fs, uniforms[idx+j])
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 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)]...)
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 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)]...)
|
||||
if j < typ.Length-1 {
|
||||
fs = append(fs, 0)
|
||||
}
|
||||
}
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
fs = append(fs, 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,
|
||||
u[0], u[2], 0, 0,
|
||||
u[1], u[3], 0, 0,
|
||||
)
|
||||
}
|
||||
if typ.Length > 0 {
|
||||
fs = fs[:len(fs)-2]
|
||||
}
|
||||
case shaderir.Mat3:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
u := uniforms[idx+9*j : idx+9*(j+1)]
|
||||
fs = append(fs,
|
||||
u[0], u[3], u[6], 0,
|
||||
u[1], u[4], u[7], 0,
|
||||
u[2], u[5], u[8], 0,
|
||||
)
|
||||
}
|
||||
if typ.Length > 0 {
|
||||
fs = fs[:len(fs)-1]
|
||||
}
|
||||
case shaderir.Mat4:
|
||||
for j := 0; j < typ.Length; j++ {
|
||||
u := uniforms[idx+16*j : idx+16*(j+1)]
|
||||
fs = append(fs,
|
||||
u[0], u[4], u[8], u[12],
|
||||
u[1], u[5], u[9], u[13],
|
||||
u[2], u[6], u[10], u[14],
|
||||
u[3], u[7], u[11], u[15],
|
||||
)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
|
||||
idx += n
|
||||
}
|
||||
return fs
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright 2018 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 graphicsdriver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type DstRegion struct {
|
||||
Region image.Rectangle
|
||||
IndexCount int
|
||||
}
|
||||
|
||||
type FillRule int
|
||||
|
||||
const (
|
||||
FillAll FillRule = iota
|
||||
NonZero
|
||||
EvenOdd
|
||||
)
|
||||
|
||||
func (f FillRule) String() string {
|
||||
switch f {
|
||||
case FillAll:
|
||||
return "FillAll"
|
||||
case NonZero:
|
||||
return "NonZero"
|
||||
case EvenOdd:
|
||||
return "EvenOdd"
|
||||
default:
|
||||
return fmt.Sprintf("FillRule(%d)", f)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
InvalidImageID = 0
|
||||
InvalidShaderID = 0
|
||||
)
|
||||
|
||||
type Graphics interface {
|
||||
Initialize() error
|
||||
Begin() error
|
||||
End(present bool) error
|
||||
SetTransparent(transparent bool)
|
||||
SetVertices(vertices []float32, indices []uint32) error
|
||||
NewImage(width, height int) (Image, error)
|
||||
NewScreenFramebufferImage(width, height int) (Image, error)
|
||||
SetVsyncEnabled(enabled bool)
|
||||
NeedsClearingScreen() bool
|
||||
MaxImageSize() int
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type Resetter interface {
|
||||
Reset() error
|
||||
}
|
||||
|
||||
type Image interface {
|
||||
ID() ImageID
|
||||
Dispose()
|
||||
ReadPixels(args []PixelsArgs) error
|
||||
WritePixels(args []PixelsArgs) error
|
||||
}
|
||||
|
||||
type ImageID int
|
||||
|
||||
type PixelsArgs struct {
|
||||
Pixels []byte
|
||||
Region image.Rectangle
|
||||
}
|
||||
|
||||
type Shader interface {
|
||||
ID() ShaderID
|
||||
Dispose()
|
||||
}
|
||||
|
||||
type ShaderID int
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
These packages are copied from Dmitri Shuralyov's mtl packages and edited with Dmitri's permission:
|
||||
|
||||
* `github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca` (copied from `dmitri.shuralyov.com/gpu/mtl/example/movingtriangle/internal/ca`)
|
||||
* `github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl` (copied from `dmitri.shuralyov.com/gpu/mtl`)
|
||||
* `github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ns` (copied from `dmitri.shuralyov.com/gpu/mtl/example/movingtriangle/internal/ns`)
|
||||
Generated
Vendored
+218
@@ -0,0 +1,218 @@
|
||||
// Copyright 2018 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 ca provides access to Apple's Core Animation API (https://developer.apple.com/documentation/quartzcore).
|
||||
//
|
||||
// This package is in very early stages of development.
|
||||
// It's a minimal implementation with scope limited to
|
||||
// supporting the movingtriangle example.
|
||||
package ca
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
// 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.
|
||||
type Layer interface {
|
||||
// Layer returns the underlying CALayer * pointer.
|
||||
Layer() unsafe.Pointer
|
||||
}
|
||||
|
||||
// MetalLayer is a Core Animation Metal layer, a layer that manages a pool of Metal drawables.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
|
||||
type MetalLayer struct {
|
||||
metalLayer objc.ID
|
||||
}
|
||||
|
||||
// MakeMetalLayer creates a new Core Animation Metal layer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
|
||||
func MakeMetalLayer() (MetalLayer, error) {
|
||||
coreGraphics, err := purego.Dlopen("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
cgColorSpaceCreateWithName, err := purego.Dlsym(coreGraphics, "CGColorSpaceCreateWithName")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
cgColorSpaceRelease, err := purego.Dlsym(coreGraphics, "CGColorSpaceRelease")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
kCGColorSpaceDisplayP3, err := purego.Dlsym(coreGraphics, "kCGColorSpaceDisplayP3")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
layer := objc.ID(objc.GetClass("CAMetalLayer")).Send(objc.RegisterName("new"))
|
||||
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)
|
||||
purego.SyscallN(cgColorSpaceRelease, colorspace)
|
||||
}
|
||||
return MetalLayer{layer}, nil
|
||||
}
|
||||
|
||||
// Layer implements the Layer interface.
|
||||
func (ml MetalLayer) Layer() unsafe.Pointer {
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&ml.metalLayer))
|
||||
}
|
||||
|
||||
// PixelFormat returns the pixel format of textures for rendering layer content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
|
||||
func (ml MetalLayer) PixelFormat() mtl.PixelFormat {
|
||||
return mtl.PixelFormat(ml.metalLayer.Send(objc.RegisterName("pixelFormat")))
|
||||
}
|
||||
|
||||
// SetDevice sets the Metal device responsible for the layer's drawable resources.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device.
|
||||
func (ml MetalLayer) SetDevice(device mtl.Device) {
|
||||
ml.metalLayer.Send(objc.RegisterName("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)
|
||||
}
|
||||
|
||||
// SetPixelFormat controls the pixel format of textures for rendering layer content.
|
||||
//
|
||||
// The pixel format for a Metal layer must be PixelFormatBGRA8UNorm, PixelFormatBGRA8UNormSRGB,
|
||||
// PixelFormatRGBA16Float, PixelFormatBGRA10XR, or PixelFormatBGRA10XRSRGB.
|
||||
// SetPixelFormat panics for other values.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
|
||||
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)))
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("setPixelFormat:"), uint(pf))
|
||||
}
|
||||
|
||||
// SetMaximumDrawableCount controls the number of Metal drawables in the resource pool
|
||||
// managed by Core Animation.
|
||||
//
|
||||
// It can set to 2 or 3 only. SetMaximumDrawableCount panics for other values.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount.
|
||||
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)))
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("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.
|
||||
func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) {
|
||||
if runtime.GOOS == "ios" {
|
||||
return
|
||||
}
|
||||
ml.metalLayer.Send(objc.RegisterName("setDisplaySyncEnabled:"), enabled)
|
||||
}
|
||||
|
||||
// SetDrawableSize sets the size, in pixels, of textures for rendering layer content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize.
|
||||
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()
|
||||
}
|
||||
|
||||
// NextDrawable returns a Metal drawable.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable.
|
||||
func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
|
||||
md := ml.metalLayer.Send(objc.RegisterName("nextDrawable"))
|
||||
if md == 0 {
|
||||
return MetalDrawable{}, errors.New("nextDrawable returned nil")
|
||||
}
|
||||
return MetalDrawable{md}, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
func (ml MetalLayer) PresentsWithTransaction() bool {
|
||||
return ml.metalLayer.Send(objc.RegisterName("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
|
||||
func (ml MetalLayer) SetPresentsWithTransaction(presentsWithTransaction bool) {
|
||||
ml.metalLayer.Send(objc.RegisterName("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
|
||||
func (ml MetalLayer) SetFramebufferOnly(framebufferOnly bool) {
|
||||
ml.metalLayer.Send(objc.RegisterName("setFramebufferOnly:"), framebufferOnly)
|
||||
}
|
||||
|
||||
// MetalDrawable is a displayable resource that can be rendered or written to by Metal.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable.
|
||||
type MetalDrawable struct {
|
||||
metalDrawable objc.ID
|
||||
}
|
||||
|
||||
// Drawable implements the mtl.Drawable interface.
|
||||
func (md MetalDrawable) Drawable() unsafe.Pointer {
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&md.metalDrawable))
|
||||
}
|
||||
|
||||
// Texture returns a Metal texture object representing the drawable object's content.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture.
|
||||
func (md MetalDrawable) Texture() mtl.Texture {
|
||||
return mtl.NewTexture(md.metalDrawable.Send(objc.RegisterName("texture")))
|
||||
}
|
||||
|
||||
// Present presents the drawable onscreen as soon as possible.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/metal/mtldrawable/1470284-present.
|
||||
func (md MetalDrawable) Present() {
|
||||
md.metalDrawable.Send(objc.RegisterName("present"))
|
||||
}
|
||||
Generated
Vendored
+918
@@ -0,0 +1,918 @@
|
||||
// Copyright 2018 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 metal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"runtime"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"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"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type Graphics struct {
|
||||
view view
|
||||
|
||||
cq mtl.CommandQueue
|
||||
cb mtl.CommandBuffer
|
||||
rce mtl.RenderCommandEncoder
|
||||
dsss map[stencilMode]mtl.DepthStencilState
|
||||
|
||||
screenDrawable ca.MetalDrawable
|
||||
|
||||
buffers map[mtl.CommandBuffer][]mtl.Buffer
|
||||
unusedBuffers map[mtl.Buffer]struct{}
|
||||
|
||||
lastDst *Image
|
||||
lastFillRule graphicsdriver.FillRule
|
||||
|
||||
vb mtl.Buffer
|
||||
ib mtl.Buffer
|
||||
|
||||
images map[graphicsdriver.ImageID]*Image
|
||||
nextImageID graphicsdriver.ImageID
|
||||
|
||||
shaders map[graphicsdriver.ShaderID]*Shader
|
||||
nextShaderID graphicsdriver.ShaderID
|
||||
|
||||
transparent bool
|
||||
maxImageSize int
|
||||
tmpTextures []mtl.Texture
|
||||
|
||||
pool cocoa.NSAutoreleasePool
|
||||
}
|
||||
|
||||
type stencilMode int
|
||||
|
||||
const (
|
||||
noStencil stencilMode = iota
|
||||
incrementStencil
|
||||
invertStencil
|
||||
drawWithStencil
|
||||
)
|
||||
|
||||
var (
|
||||
systemDefaultDevice mtl.Device
|
||||
systemDefaultDeviceErr error
|
||||
)
|
||||
|
||||
func init() {
|
||||
// mtl.CreateSystemDefaultDevice must be called on the main thread (#2147).
|
||||
d, err := mtl.CreateSystemDefaultDevice()
|
||||
if err != nil {
|
||||
systemDefaultDeviceErr = err
|
||||
return
|
||||
}
|
||||
systemDefaultDevice = d
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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.
|
||||
if systemDefaultDeviceErr != nil {
|
||||
return nil, fmt.Errorf("metal: mtl.CreateSystemDefaultDevice failed: %w", systemDefaultDeviceErr)
|
||||
}
|
||||
|
||||
g := &Graphics{}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) Begin() error {
|
||||
// NSAutoreleasePool is required to release drawable correctly (#847).
|
||||
// https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html
|
||||
g.pool = cocoa.NSAutoreleasePool_new()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) End(present bool) error {
|
||||
g.flushIfNeeded(present)
|
||||
g.screenDrawable = ca.MetalDrawable{}
|
||||
g.pool.Release()
|
||||
g.pool.ID = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetWindow(window uintptr) {
|
||||
// Note that [NSApp mainWindow] returns nil when the window is borderless.
|
||||
// Then the window is needed to be given explicitly.
|
||||
g.view.setWindow(window)
|
||||
}
|
||||
|
||||
func (g *Graphics) SetUIView(uiview uintptr) {
|
||||
// TODO: Should this be called on the main thread?
|
||||
g.view.setUIView(uiview)
|
||||
}
|
||||
|
||||
func pow2(x uintptr) uintptr {
|
||||
if x > (math.MaxUint+1)/2 {
|
||||
return math.MaxUint
|
||||
}
|
||||
|
||||
var p2 uintptr = 1
|
||||
for p2 < x {
|
||||
p2 *= 2
|
||||
}
|
||||
return p2
|
||||
}
|
||||
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, b := range bs {
|
||||
if g.unusedBuffers == nil {
|
||||
g.unusedBuffers = map[mtl.Buffer]struct{}{}
|
||||
}
|
||||
g.unusedBuffers[b] = struct{}{}
|
||||
}
|
||||
delete(g.buffers, cb)
|
||||
cb.Release()
|
||||
}
|
||||
|
||||
const maxUnusedBuffers = 10
|
||||
if len(g.unusedBuffers) > maxUnusedBuffers {
|
||||
bufs := make([]mtl.Buffer, 0, len(g.unusedBuffers))
|
||||
for b := range g.unusedBuffers {
|
||||
bufs = append(bufs, b)
|
||||
}
|
||||
sort.Slice(bufs, func(a, b int) bool {
|
||||
return bufs[a].Length() > bufs[b].Length()
|
||||
})
|
||||
for _, b := range bufs[maxUnusedBuffers:] {
|
||||
delete(g.unusedBuffers, b)
|
||||
b.Release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) availableBuffer(length uintptr) mtl.Buffer {
|
||||
if g.cb == (mtl.CommandBuffer{}) {
|
||||
g.cb = g.cq.MakeCommandBuffer()
|
||||
}
|
||||
|
||||
var newBuf mtl.Buffer
|
||||
for b := range g.unusedBuffers {
|
||||
if b.Length() >= length {
|
||||
newBuf = b
|
||||
delete(g.unusedBuffers, b)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if newBuf == (mtl.Buffer{}) {
|
||||
newBuf = g.view.getMTLDevice().MakeBufferWithLength(pow2(length), resourceStorageMode)
|
||||
}
|
||||
|
||||
if g.buffers == nil {
|
||||
g.buffers = map[mtl.CommandBuffer][]mtl.Buffer{}
|
||||
}
|
||||
if _, ok := g.buffers[g.cb]; !ok {
|
||||
g.cb.Retain()
|
||||
}
|
||||
g.buffers[g.cb] = append(g.buffers[g.cb], newBuf)
|
||||
return newBuf
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVertices(vertices []float32, indices []uint32) error {
|
||||
vbSize := unsafe.Sizeof(vertices[0]) * uintptr(len(vertices))
|
||||
ibSize := unsafe.Sizeof(indices[0]) * uintptr(len(indices))
|
||||
|
||||
g.vb = g.availableBuffer(vbSize)
|
||||
g.vb.CopyToContents(unsafe.Pointer(&vertices[0]), vbSize)
|
||||
|
||||
g.ib = g.availableBuffer(ibSize)
|
||||
g.ib.CopyToContents(unsafe.Pointer(&indices[0]), ibSize)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) flushIfNeeded(present bool) {
|
||||
if g.cb == (mtl.CommandBuffer{}) && !present {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
g.cb.Commit()
|
||||
|
||||
for _, t := range g.tmpTextures {
|
||||
t.Release()
|
||||
}
|
||||
g.tmpTextures = g.tmpTextures[:0]
|
||||
|
||||
g.cb = mtl.CommandBuffer{}
|
||||
}
|
||||
|
||||
func (g *Graphics) checkSize(width, height int) {
|
||||
if width < 1 {
|
||||
panic(fmt.Sprintf("metal: width (%d) must be equal or more than %d", width, 1))
|
||||
}
|
||||
if height < 1 {
|
||||
panic(fmt.Sprintf("metal: height (%d) must be equal or more than %d", height, 1))
|
||||
}
|
||||
m := g.MaxImageSize()
|
||||
if width > m {
|
||||
panic(fmt.Sprintf("metal: width (%d) must be less than or equal to %d", width, m))
|
||||
}
|
||||
if height > m {
|
||||
panic(fmt.Sprintf("metal: height (%d) must be less than or equal to %d", height, m))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) genNextImageID() graphicsdriver.ImageID {
|
||||
g.nextImageID++
|
||||
return g.nextImageID
|
||||
}
|
||||
|
||||
func (g *Graphics) genNextShaderID() graphicsdriver.ShaderID {
|
||||
g.nextShaderID++
|
||||
return g.nextShaderID
|
||||
}
|
||||
|
||||
func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
g.checkSize(width, height)
|
||||
td := mtl.TextureDescriptor{
|
||||
TextureType: mtl.TextureType2D,
|
||||
PixelFormat: mtl.PixelFormatRGBA8UNorm,
|
||||
Width: graphics.InternalImageSize(width),
|
||||
Height: graphics.InternalImageSize(height),
|
||||
StorageMode: storageMode,
|
||||
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
t := g.view.getMTLDevice().MakeTexture(td)
|
||||
i := &Image{
|
||||
id: g.genNextImageID(),
|
||||
graphics: g,
|
||||
width: width,
|
||||
height: height,
|
||||
texture: t,
|
||||
}
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) NewScreenFramebufferImage(width, height int) (graphicsdriver.Image, error) {
|
||||
g.view.setDrawableSize(width, height)
|
||||
i := &Image{
|
||||
id: g.genNextImageID(),
|
||||
graphics: g,
|
||||
width: width,
|
||||
height: height,
|
||||
screen: true,
|
||||
}
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) addImage(img *Image) {
|
||||
if g.images == nil {
|
||||
g.images = map[graphicsdriver.ImageID]*Image{}
|
||||
}
|
||||
if _, ok := g.images[img.id]; ok {
|
||||
panic(fmt.Sprintf("metal: image ID %d was already registered", img.id))
|
||||
}
|
||||
g.images[img.id] = img
|
||||
}
|
||||
|
||||
func (g *Graphics) removeImage(img *Image) {
|
||||
delete(g.images, img.id)
|
||||
}
|
||||
|
||||
func (g *Graphics) SetTransparent(transparent bool) {
|
||||
g.transparent = transparent
|
||||
}
|
||||
|
||||
func blendFactorToMetalBlendFactor(c graphicsdriver.BlendFactor) mtl.BlendFactor {
|
||||
switch c {
|
||||
case graphicsdriver.BlendFactorZero:
|
||||
return mtl.BlendFactorZero
|
||||
case graphicsdriver.BlendFactorOne:
|
||||
return mtl.BlendFactorOne
|
||||
case graphicsdriver.BlendFactorSourceColor:
|
||||
return mtl.BlendFactorSourceColor
|
||||
case graphicsdriver.BlendFactorOneMinusSourceColor:
|
||||
return mtl.BlendFactorOneMinusSourceColor
|
||||
case graphicsdriver.BlendFactorSourceAlpha:
|
||||
return mtl.BlendFactorSourceAlpha
|
||||
case graphicsdriver.BlendFactorOneMinusSourceAlpha:
|
||||
return mtl.BlendFactorOneMinusSourceAlpha
|
||||
case graphicsdriver.BlendFactorDestinationColor:
|
||||
return mtl.BlendFactorDestinationColor
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationColor:
|
||||
return mtl.BlendFactorOneMinusDestinationColor
|
||||
case graphicsdriver.BlendFactorDestinationAlpha:
|
||||
return mtl.BlendFactorDestinationAlpha
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationAlpha:
|
||||
return mtl.BlendFactorOneMinusDestinationAlpha
|
||||
case graphicsdriver.BlendFactorSourceAlphaSaturated:
|
||||
return mtl.BlendFactorSourceAlphaSaturated
|
||||
default:
|
||||
panic(fmt.Sprintf("metal: invalid blend factor: %d", c))
|
||||
}
|
||||
}
|
||||
|
||||
func blendOperationToMetalBlendOperation(o graphicsdriver.BlendOperation) mtl.BlendOperation {
|
||||
switch o {
|
||||
case graphicsdriver.BlendOperationAdd:
|
||||
return mtl.BlendOperationAdd
|
||||
case graphicsdriver.BlendOperationSubtract:
|
||||
return mtl.BlendOperationSubtract
|
||||
case graphicsdriver.BlendOperationReverseSubtract:
|
||||
return mtl.BlendOperationReverseSubtract
|
||||
case graphicsdriver.BlendOperationMin:
|
||||
return mtl.BlendOperationMin
|
||||
case graphicsdriver.BlendOperationMax:
|
||||
return mtl.BlendOperationMax
|
||||
default:
|
||||
panic(fmt.Sprintf("metal: invalid blend operation: %d", o))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) Initialize() error {
|
||||
// Creating *State objects are expensive and reuse them whenever possible.
|
||||
// See https://developer.apple.com/library/archive/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Cmd-Submiss/Cmd-Submiss.html
|
||||
|
||||
for _, dss := range g.dsss {
|
||||
dss.Release()
|
||||
}
|
||||
if g.dsss == nil {
|
||||
g.dsss = map[stencilMode]mtl.DepthStencilState{}
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if g.transparent {
|
||||
g.view.ml.SetOpaque(false)
|
||||
}
|
||||
|
||||
// The stencil reference value is always 0 (default).
|
||||
g.dsss[noStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
FrontFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[incrementStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationDecrementWrap,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
FrontFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationIncrementWrap,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[invertStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationInvert,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
FrontFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationInvert,
|
||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||
},
|
||||
})
|
||||
g.dsss[drawWithStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||
BackFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
||||
},
|
||||
FrontFaceStencil: mtl.StencilDescriptor{
|
||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
||||
},
|
||||
})
|
||||
|
||||
g.cq = g.view.getMTLDevice().MakeCommandQueue()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
|
||||
if g.rce == (mtl.RenderCommandEncoder{}) {
|
||||
return
|
||||
}
|
||||
g.rce.EndEncoding()
|
||||
g.rce = mtl.RenderCommandEncoder{}
|
||||
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 {
|
||||
// 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 {
|
||||
g.flushRenderCommandEncoderIfNeeded()
|
||||
}
|
||||
g.lastDst = dst
|
||||
g.lastFillRule = fillRule
|
||||
|
||||
if g.rce == (mtl.RenderCommandEncoder{}) {
|
||||
rpd := mtl.RenderPassDescriptor{}
|
||||
// Even though the destination pixels are not used, mtl.LoadActionDontCare might cause glitches
|
||||
// (#1019). Always using mtl.LoadActionLoad is safe.
|
||||
if dst.screen {
|
||||
rpd.ColorAttachments[0].LoadAction = mtl.LoadActionClear
|
||||
} else {
|
||||
rpd.ColorAttachments[0].LoadAction = mtl.LoadActionLoad
|
||||
}
|
||||
|
||||
// The store action should always be 'store' even for the screen (#1700).
|
||||
rpd.ColorAttachments[0].StoreAction = mtl.StoreActionStore
|
||||
|
||||
t := dst.mtlTexture()
|
||||
if t == (mtl.Texture{}) {
|
||||
return nil
|
||||
}
|
||||
rpd.ColorAttachments[0].Texture = t
|
||||
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
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)
|
||||
}
|
||||
|
||||
w, h := dst.internalSize()
|
||||
g.rce.SetViewport(mtl.Viewport{
|
||||
OriginX: 0,
|
||||
OriginY: 0,
|
||||
Width: float64(w),
|
||||
Height: float64(h),
|
||||
ZNear: -1,
|
||||
ZFar: 1,
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
||||
for i, src := range srcs {
|
||||
if src != nil {
|
||||
g.rce.SetFragmentTexture(src.texture, i)
|
||||
} else {
|
||||
g.rce.SetFragmentTexture(mtl.Texture{}, i)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
noStencilRpss mtl.RenderPipelineState
|
||||
incrementStencilRpss mtl.RenderPipelineState
|
||||
invertStencilRpss mtl.RenderPipelineState
|
||||
drawWithStencilRpss mtl.RenderPipelineState
|
||||
)
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
noStencilRpss = s
|
||||
case graphicsdriver.NonZero:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, incrementStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
incrementStencilRpss = s
|
||||
case graphicsdriver.EvenOdd:
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, invertStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
invertStencilRpss = s
|
||||
}
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
drawWithStencilRpss = s
|
||||
}
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.rce.SetScissorRect(mtl.ScissorRect{
|
||||
X: dstRegion.Region.Min.X,
|
||||
Y: dstRegion.Region.Min.Y,
|
||||
Width: dstRegion.Region.Dx(),
|
||||
Height: dstRegion.Region.Dy(),
|
||||
})
|
||||
|
||||
switch fillRule {
|
||||
case graphicsdriver.FillAll:
|
||||
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:
|
||||
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:
|
||||
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 {
|
||||
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))))
|
||||
}
|
||||
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
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 {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("metal: shader ID is invalid")
|
||||
}
|
||||
|
||||
dst := g.images[dstID]
|
||||
|
||||
if dst.screen {
|
||||
g.view.update()
|
||||
}
|
||||
|
||||
var srcs [graphics.ShaderImageCount]*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 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
||||
g.view.setDisplaySyncEnabled(enabled)
|
||||
}
|
||||
|
||||
func (g *Graphics) NeedsClearingScreen() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *Graphics) MaxImageSize() int {
|
||||
if g.maxImageSize != 0 {
|
||||
return g.maxImageSize
|
||||
}
|
||||
|
||||
d := g.view.getMTLDevice()
|
||||
|
||||
// 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:")) {
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
g.maxImageSize = 8192
|
||||
switch {
|
||||
case d.SupportsFamily(mtl.GPUFamilyApple3):
|
||||
g.maxImageSize = 16384
|
||||
case d.SupportsFamily(mtl.GPUFamilyMac2):
|
||||
g.maxImageSize = 16384
|
||||
}
|
||||
return g.maxImageSize
|
||||
}
|
||||
|
||||
// supportsFeatureSet is deprecated but some old macOS/iOS versions support only this (#2553).
|
||||
switch {
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily5_v1):
|
||||
g.maxImageSize = 16384
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily4_v1):
|
||||
g.maxImageSize = 16384
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily3_v1):
|
||||
g.maxImageSize = 16384
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily2_v2):
|
||||
g.maxImageSize = 8192
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily2_v1):
|
||||
g.maxImageSize = 4096
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily1_v2):
|
||||
g.maxImageSize = 8192
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_iOS_GPUFamily1_v1):
|
||||
g.maxImageSize = 4096
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_tvOS_GPUFamily2_v1):
|
||||
g.maxImageSize = 16384
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_tvOS_GPUFamily1_v1):
|
||||
g.maxImageSize = 8192
|
||||
case d.SupportsFeatureSet(mtl.FeatureSet_macOS_GPUFamily1_v1):
|
||||
g.maxImageSize = 16384
|
||||
default:
|
||||
panic("metal: there is no supported feature set")
|
||||
}
|
||||
return g.maxImageSize
|
||||
}
|
||||
|
||||
func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
s, err := newShader(g.view.getMTLDevice(), g.genNextShaderID(), program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.addShader(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) addShader(shader *Shader) {
|
||||
if g.shaders == nil {
|
||||
g.shaders = map[graphicsdriver.ShaderID]*Shader{}
|
||||
}
|
||||
if _, ok := g.shaders[shader.id]; ok {
|
||||
panic(fmt.Sprintf("metal: shader ID %d was already registered", shader.id))
|
||||
}
|
||||
g.shaders[shader.id] = shader
|
||||
}
|
||||
|
||||
func (g *Graphics) removeShader(shader *Shader) {
|
||||
delete(g.shaders, shader.id)
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
id graphicsdriver.ImageID
|
||||
graphics *Graphics
|
||||
width int
|
||||
height int
|
||||
screen bool
|
||||
texture mtl.Texture
|
||||
stencil mtl.Texture
|
||||
}
|
||||
|
||||
func (i *Image) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *Image) internalSize() (int, int) {
|
||||
if i.screen {
|
||||
return i.width, i.height
|
||||
}
|
||||
return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||
}
|
||||
|
||||
func (i *Image) Dispose() {
|
||||
if i.stencil != (mtl.Texture{}) {
|
||||
i.stencil.Release()
|
||||
i.stencil = mtl.Texture{}
|
||||
}
|
||||
if i.texture != (mtl.Texture{}) {
|
||||
i.texture.Release()
|
||||
i.texture = mtl.Texture{}
|
||||
}
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *Image) syncTexture() {
|
||||
i.graphics.flushRenderCommandEncoderIfNeeded()
|
||||
|
||||
// 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?")
|
||||
}
|
||||
|
||||
cb := i.graphics.cq.MakeCommandBuffer()
|
||||
bce := cb.MakeBlitCommandEncoder()
|
||||
bce.SynchronizeTexture(i.texture, 0, 0)
|
||||
bce.EndEncoding()
|
||||
|
||||
cb.Commit()
|
||||
// TODO: Are fences available here?
|
||||
cb.WaitUntilCompleted()
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
i.graphics.flushIfNeeded(false)
|
||||
i.syncTexture()
|
||||
|
||||
for _, arg := range args {
|
||||
if got, want := len(arg.Pixels), 4*arg.Region.Dx()*arg.Region.Dy(); got != want {
|
||||
return fmt.Errorf("metal: len(buf) must be %d but %d at ReadPixels", want, got)
|
||||
}
|
||||
i.texture.GetBytes(&arg.Pixels[0], uintptr(4*arg.Region.Dx()), mtl.Region{
|
||||
Origin: mtl.Origin{X: arg.Region.Min.X, Y: arg.Region.Min.Y},
|
||||
Size: mtl.Size{Width: arg.Region.Dx(), Height: arg.Region.Dy(), Depth: 1},
|
||||
}, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
g := i.graphics
|
||||
|
||||
g.flushRenderCommandEncoderIfNeeded()
|
||||
|
||||
// Calculate the smallest texture size to include all the values in args.
|
||||
var region image.Rectangle
|
||||
for _, a := range args {
|
||||
region = region.Union(a.Region)
|
||||
}
|
||||
|
||||
// Use a temporary texture to send pixels asynchronously, whichever the memory is shared (e.g., iOS) or
|
||||
// managed (e.g., macOS). A temporary texture is needed since ReplaceRegion tries to sync the pixel
|
||||
// data between CPU and GPU, and doing it on the existing texture is inefficient (#1418).
|
||||
// The texture cannot be reused until sending the pixels finishes, then create new ones for each call.
|
||||
td := mtl.TextureDescriptor{
|
||||
TextureType: mtl.TextureType2D,
|
||||
PixelFormat: mtl.PixelFormatRGBA8UNorm,
|
||||
Width: region.Dx(),
|
||||
Height: region.Dy(),
|
||||
StorageMode: storageMode,
|
||||
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
t := g.view.getMTLDevice().MakeTexture(td)
|
||||
g.tmpTextures = append(g.tmpTextures, t)
|
||||
|
||||
for _, a := range args {
|
||||
t.ReplaceRegion(mtl.Region{
|
||||
Origin: mtl.Origin{X: a.Region.Min.X - region.Min.X, Y: a.Region.Min.Y - region.Min.Y, Z: 0},
|
||||
Size: mtl.Size{Width: a.Region.Dx(), Height: a.Region.Dy(), Depth: 1},
|
||||
}, 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()
|
||||
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}
|
||||
do := mtl.Origin{X: a.Region.Min.X, Y: a.Region.Min.Y, Z: 0}
|
||||
bce.CopyFromTexture(t, 0, 0, so, ss, i.texture, 0, 0, do)
|
||||
}
|
||||
bce.EndEncoding()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) mtlTexture() mtl.Texture {
|
||||
if i.screen {
|
||||
g := i.graphics
|
||||
if g.screenDrawable == (ca.MetalDrawable{}) {
|
||||
drawable := g.view.nextDrawable()
|
||||
if drawable == (ca.MetalDrawable{}) {
|
||||
return mtl.Texture{}
|
||||
}
|
||||
g.screenDrawable = drawable
|
||||
// After nextDrawable, it is expected some command buffers are completed.
|
||||
g.gcBuffers()
|
||||
}
|
||||
return g.screenDrawable.Texture()
|
||||
}
|
||||
return i.texture
|
||||
}
|
||||
|
||||
func (i *Image) ensureStencil() {
|
||||
if i.stencil != (mtl.Texture{}) {
|
||||
return
|
||||
}
|
||||
|
||||
td := mtl.TextureDescriptor{
|
||||
TextureType: mtl.TextureType2D,
|
||||
PixelFormat: mtl.PixelFormatStencil8,
|
||||
Width: graphics.InternalImageSize(i.width),
|
||||
Height: graphics.InternalImageSize(i.height),
|
||||
StorageMode: mtl.StorageModePrivate,
|
||||
Usage: mtl.TextureUsageRenderTarget,
|
||||
}
|
||||
i.stencil = i.graphics.view.getMTLDevice().MakeTexture(td)
|
||||
}
|
||||
Generated
Vendored
+1238
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+130
@@ -0,0 +1,130 @@
|
||||
// Copyright 2020 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 metal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/msl"
|
||||
)
|
||||
|
||||
type shaderRpsKey struct {
|
||||
blend graphicsdriver.Blend
|
||||
stencilMode stencilMode
|
||||
screen bool
|
||||
}
|
||||
|
||||
type Shader struct {
|
||||
id graphicsdriver.ShaderID
|
||||
|
||||
ir *shaderir.Program
|
||||
fs mtl.Function
|
||||
vs mtl.Function
|
||||
rpss map[shaderRpsKey]mtl.RenderPipelineState
|
||||
}
|
||||
|
||||
func newShader(device mtl.Device, id graphicsdriver.ShaderID, program *shaderir.Program) (*Shader, error) {
|
||||
s := &Shader{
|
||||
id: id,
|
||||
ir: program,
|
||||
rpss: map[shaderRpsKey]mtl.RenderPipelineState{},
|
||||
}
|
||||
if err := s.init(device); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Shader) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *Shader) Dispose() {
|
||||
for _, rps := range s.rpss {
|
||||
rps.Release()
|
||||
}
|
||||
s.vs.Release()
|
||||
s.fs.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)
|
||||
}
|
||||
vs, err := lib.MakeFunction(msl.VertexName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for vertex failed: %w, source: %s", err, src)
|
||||
}
|
||||
fs, err := lib.MakeFunction(msl.FragmentName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metal: lib.MakeFunction for fragment failed: %w, source: %s", err, src)
|
||||
}
|
||||
s.fs = fs
|
||||
s.vs = vs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Shader) RenderPipelineState(view *view, blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (mtl.RenderPipelineState, error) {
|
||||
key := shaderRpsKey{
|
||||
blend: blend,
|
||||
stencilMode: stencilMode,
|
||||
screen: screen,
|
||||
}
|
||||
if rps, ok := s.rpss[key]; ok {
|
||||
return rps, nil
|
||||
}
|
||||
|
||||
rpld := mtl.RenderPipelineDescriptor{
|
||||
VertexFunction: s.vs,
|
||||
FragmentFunction: s.fs,
|
||||
}
|
||||
if stencilMode != noStencil {
|
||||
rpld.StencilAttachmentPixelFormat = mtl.PixelFormatStencil8
|
||||
}
|
||||
|
||||
// TODO: For the precise pixel format, whether the render target is the screen or not must be considered.
|
||||
pix := mtl.PixelFormatRGBA8UNorm
|
||||
if screen {
|
||||
pix = view.colorPixelFormat()
|
||||
}
|
||||
rpld.ColorAttachments[0].PixelFormat = pix
|
||||
rpld.ColorAttachments[0].BlendingEnabled = true
|
||||
|
||||
rpld.ColorAttachments[0].DestinationAlphaBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorDestinationAlpha)
|
||||
rpld.ColorAttachments[0].DestinationRGBBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorDestinationRGB)
|
||||
rpld.ColorAttachments[0].SourceAlphaBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorSourceAlpha)
|
||||
rpld.ColorAttachments[0].SourceRGBBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorSourceRGB)
|
||||
rpld.ColorAttachments[0].AlphaBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationAlpha)
|
||||
rpld.ColorAttachments[0].RGBBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationRGB)
|
||||
|
||||
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
|
||||
} else {
|
||||
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
|
||||
}
|
||||
|
||||
rps, err := view.getMTLDevice().MakeRenderPipelineState(rpld)
|
||||
if err != nil {
|
||||
return mtl.RenderPipelineState{}, err
|
||||
}
|
||||
|
||||
s.rpss[key] = rps
|
||||
return rps, nil
|
||||
}
|
||||
Generated
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
// 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 metal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
type view struct {
|
||||
window uintptr
|
||||
uiview uintptr
|
||||
|
||||
windowChanged bool
|
||||
vsyncDisabled bool
|
||||
|
||||
device mtl.Device
|
||||
ml ca.MetalLayer
|
||||
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (v *view) setDrawableSize(width, height int) {
|
||||
v.ml.SetDrawableSize(width, height)
|
||||
}
|
||||
|
||||
func (v *view) getMTLDevice() mtl.Device {
|
||||
return v.device
|
||||
}
|
||||
|
||||
func (v *view) setDisplaySyncEnabled(enabled bool) {
|
||||
if !v.vsyncDisabled == enabled {
|
||||
return
|
||||
}
|
||||
v.forceSetDisplaySyncEnabled(enabled)
|
||||
}
|
||||
|
||||
func (v *view) forceSetDisplaySyncEnabled(enabled bool) {
|
||||
v.ml.SetDisplaySyncEnabled(enabled)
|
||||
v.vsyncDisabled = !enabled
|
||||
}
|
||||
|
||||
func (v *view) colorPixelFormat() mtl.PixelFormat {
|
||||
return v.ml.PixelFormat()
|
||||
}
|
||||
|
||||
func (v *view) initialize(device mtl.Device) error {
|
||||
v.device = device
|
||||
|
||||
ml, err := ca.MakeMetalLayer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.ml = ml
|
||||
v.ml.SetDevice(v.device)
|
||||
// https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat
|
||||
//
|
||||
// The pixel format for a Metal layer must be MTLPixelFormatBGRA8Unorm,
|
||||
// MTLPixelFormatBGRA8Unorm_sRGB, MTLPixelFormatRGBA16Float, MTLPixelFormatBGRA10_XR, or
|
||||
// MTLPixelFormatBGRA10_XR_sRGB.
|
||||
v.ml.SetPixelFormat(mtl.PixelFormatBGRA8UNorm)
|
||||
|
||||
// The vsync state might be reset. Set the state again (#1364).
|
||||
v.forceSetDisplaySyncEnabled(!v.vsyncDisabled)
|
||||
v.ml.SetFramebufferOnly(true)
|
||||
|
||||
// presentsWithTransaction doesn't work in the fullscreen mode (#1745, #1974).
|
||||
// presentsWithTransaction doesn't work with vsync off (#1196).
|
||||
// nextDrawable took more than one second if the window has other controls like NSTextView (#1029).
|
||||
v.ml.SetPresentsWithTransaction(false)
|
||||
|
||||
v.ml.SetMaximumDrawableCount(v.maximumDrawableCount())
|
||||
|
||||
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
|
||||
}
|
||||
Generated
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
// 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 metal
|
||||
|
||||
// Suppress the warnings about availability guard with -Wno-unguarded-availability-new.
|
||||
// It is because old Xcode (8 or older?) does not accept @available syntax.
|
||||
|
||||
// #cgo CFLAGS: -Wno-unguarded-availability-new -x objective-c
|
||||
// #cgo LDFLAGS: -framework UIKit -framework QuartzCore -framework Foundation -framework CoreGraphics
|
||||
//
|
||||
// #import <UIKit/UIKit.h>
|
||||
//
|
||||
// static void addSublayer(void* view, void* sublayer) {
|
||||
// CALayer* layer = ((UIView*)view).layer;
|
||||
// [layer addSublayer:(CALayer*)sublayer];
|
||||
// }
|
||||
//
|
||||
// static void setFrame(void* cametal, void* uiview) {
|
||||
// __block CGSize size;
|
||||
// dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
// size = ((UIView*)uiview).frame.size;
|
||||
// });
|
||||
// ((CALayer*)cametal).frame = CGRectMake(0, 0, size.width, size.height);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
func (v *view) setWindow(window uintptr) {
|
||||
panic("metal: setWindow is not available on iOS")
|
||||
}
|
||||
|
||||
func (v *view) setUIView(uiview uintptr) {
|
||||
v.uiview = uiview
|
||||
}
|
||||
|
||||
func (v *view) update() {
|
||||
v.once.Do(func() {
|
||||
if v.ml.Layer() == nil {
|
||||
panic("metal: CAMetalLayer is not initialized yet")
|
||||
}
|
||||
C.addSublayer(unsafe.Pointer(v.uiview), v.ml.Layer())
|
||||
})
|
||||
C.setFrame(v.ml.Layer(), unsafe.Pointer(v.uiview))
|
||||
}
|
||||
|
||||
const (
|
||||
storageMode = mtl.StorageModeShared
|
||||
resourceStorageMode = mtl.ResourceStorageModeShared
|
||||
)
|
||||
|
||||
func (v *view) maximumDrawableCount() int {
|
||||
// TODO: Is 2 available for iOS?
|
||||
return 3
|
||||
}
|
||||
Generated
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
// 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.
|
||||
|
||||
//go:build darwin && !ios
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
func (v *view) setWindow(window uintptr) {
|
||||
// NSView can be updated e.g., fullscreen-state is switched.
|
||||
v.window = window
|
||||
v.windowChanged = true
|
||||
}
|
||||
|
||||
func (v *view) setUIView(uiview uintptr) {
|
||||
panic("metal: setUIView is not available on macOS")
|
||||
}
|
||||
|
||||
func (v *view) update() {
|
||||
v.ml.SetMaximumDrawableCount(v.maximumDrawableCount())
|
||||
|
||||
if !v.windowChanged {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Should this be called on the main thread?
|
||||
cocoaWindow := cocoa.NSWindow{ID: objc.ID(v.window)}
|
||||
cocoaWindow.ContentView().SetLayer(uintptr(v.ml.Layer()))
|
||||
cocoaWindow.ContentView().SetWantsLayer(true)
|
||||
|
||||
v.windowChanged = false
|
||||
}
|
||||
|
||||
const (
|
||||
storageMode = mtl.StorageModeManaged
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (v *view) isFullscreen() bool {
|
||||
return cocoa.NSWindow{ID: objc.ID(v.window)}.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0
|
||||
}
|
||||
Generated
Vendored
+498
@@ -0,0 +1,498 @@
|
||||
// Copyright 2016 Hajime Hoshi
|
||||
//
|
||||
// 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 opengl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/glsl"
|
||||
)
|
||||
|
||||
type blendFactor int
|
||||
|
||||
type blendOperation int
|
||||
|
||||
func convertBlendFactor(f graphicsdriver.BlendFactor) blendFactor {
|
||||
switch f {
|
||||
case graphicsdriver.BlendFactorZero:
|
||||
return gl.ZERO
|
||||
case graphicsdriver.BlendFactorOne:
|
||||
return gl.ONE
|
||||
case graphicsdriver.BlendFactorSourceColor:
|
||||
return gl.SRC_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusSourceColor:
|
||||
return gl.ONE_MINUS_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorSourceAlpha:
|
||||
return gl.SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusSourceAlpha:
|
||||
return gl.ONE_MINUS_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorDestinationColor:
|
||||
return gl.DST_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationColor:
|
||||
return gl.ONE_MINUS_DST_COLOR
|
||||
case graphicsdriver.BlendFactorDestinationAlpha:
|
||||
return gl.DST_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationAlpha:
|
||||
return gl.ONE_MINUS_DST_ALPHA
|
||||
case graphicsdriver.BlendFactorSourceAlphaSaturated:
|
||||
return gl.SRC_ALPHA_SATURATE
|
||||
default:
|
||||
panic(fmt.Sprintf("opengl: invalid blend factor %d", f))
|
||||
}
|
||||
}
|
||||
|
||||
func convertBlendOperation(o graphicsdriver.BlendOperation) blendOperation {
|
||||
switch o {
|
||||
case graphicsdriver.BlendOperationAdd:
|
||||
return gl.FUNC_ADD
|
||||
case graphicsdriver.BlendOperationSubtract:
|
||||
return gl.FUNC_SUBTRACT
|
||||
case graphicsdriver.BlendOperationReverseSubtract:
|
||||
return gl.FUNC_REVERSE_SUBTRACT
|
||||
case graphicsdriver.BlendOperationMin:
|
||||
return gl.MIN
|
||||
case graphicsdriver.BlendOperationMax:
|
||||
return gl.MAX
|
||||
default:
|
||||
panic(fmt.Sprintf("opengl: invalid blend operation %d", o))
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
textureNative uint32
|
||||
renderbufferNative uint32
|
||||
framebufferNative uint32
|
||||
shader uint32
|
||||
program uint32
|
||||
buffer uint32
|
||||
)
|
||||
|
||||
type (
|
||||
uniformLocation int32
|
||||
attribLocation int32
|
||||
)
|
||||
|
||||
const (
|
||||
invalidFramebuffer = (1 << 32) - 1
|
||||
invalidUniform = -1
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (c *context) bindTexture(t textureNative) {
|
||||
if c.lastTexture == t {
|
||||
return
|
||||
}
|
||||
c.ctx.BindTexture(gl.TEXTURE_2D, uint32(t))
|
||||
c.lastTexture = t
|
||||
}
|
||||
|
||||
func (c *context) bindRenderbuffer(r renderbufferNative) {
|
||||
if c.lastRenderbuffer == r {
|
||||
return
|
||||
}
|
||||
c.ctx.BindRenderbuffer(gl.RENDERBUFFER, uint32(r))
|
||||
c.lastRenderbuffer = r
|
||||
}
|
||||
|
||||
func (c *context) bindFramebuffer(f framebufferNative) {
|
||||
if c.lastFramebuffer == f {
|
||||
return
|
||||
}
|
||||
c.ctx.BindFramebuffer(gl.FRAMEBUFFER, uint32(f))
|
||||
c.lastFramebuffer = f
|
||||
}
|
||||
|
||||
func (c *context) setViewport(f *framebuffer) {
|
||||
c.bindFramebuffer(f.native)
|
||||
if c.lastViewportWidth == f.width && c.lastViewportHeight == f.height {
|
||||
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))
|
||||
|
||||
// glViewport must be called at least at every frame on iOS.
|
||||
// As the screen framebuffer is the last render target, next SetViewport should be
|
||||
// the first call at a frame.
|
||||
if f.native == c.screenFramebuffer {
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
} else {
|
||||
c.lastViewportWidth = f.width
|
||||
c.lastViewportHeight = f.height
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) newScreenFramebuffer(width, height int) *framebuffer {
|
||||
return &framebuffer{
|
||||
native: c.screenFramebuffer,
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) getMaxTextureSize() int {
|
||||
c.maxTextureSizeOnce.Do(func() {
|
||||
c.maxTextureSize = c.ctx.GetInteger(gl.MAX_TEXTURE_SIZE)
|
||||
})
|
||||
return c.maxTextureSize
|
||||
}
|
||||
|
||||
func (c *context) reset() error {
|
||||
var err1 error
|
||||
c.initOnce.Do(func() {
|
||||
// Load OpenGL functions after WGL is initialized especially for Windows (#2452).
|
||||
if err := c.ctx.LoadFunctions(); err != nil {
|
||||
err1 = err
|
||||
return
|
||||
}
|
||||
})
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
||||
c.locationCache = newLocationCache()
|
||||
c.lastTexture = 0
|
||||
c.lastFramebuffer = invalidFramebuffer
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
c.lastBlend = graphicsdriver.Blend{}
|
||||
|
||||
c.ctx.Enable(gl.BLEND)
|
||||
c.ctx.Enable(gl.SCISSOR_TEST)
|
||||
c.blend(graphicsdriver.BlendSourceOver)
|
||||
c.screenFramebuffer = framebufferNative(c.ctx.GetInteger(gl.FRAMEBUFFER_BINDING))
|
||||
// TODO: Need to update screenFramebufferWidth/Height?
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) blend(blend graphicsdriver.Blend) {
|
||||
if c.lastBlend == blend {
|
||||
return
|
||||
}
|
||||
c.lastBlend = blend
|
||||
c.ctx.BlendFuncSeparate(
|
||||
uint32(convertBlendFactor(blend.BlendFactorSourceRGB)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorDestinationRGB)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorSourceAlpha)),
|
||||
uint32(convertBlendFactor(blend.BlendFactorDestinationAlpha)),
|
||||
)
|
||||
c.ctx.BlendEquationSeparate(
|
||||
uint32(convertBlendOperation(blend.BlendOperationRGB)),
|
||||
uint32(convertBlendOperation(blend.BlendOperationAlpha)),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *context) newTexture(width, height int) (textureNative, error) {
|
||||
t := c.ctx.CreateTexture()
|
||||
if t <= 0 {
|
||||
return 0, errors.New("opengl: creating texture failed")
|
||||
}
|
||||
c.bindTexture(textureNative(t))
|
||||
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
c.ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
c.ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 4)
|
||||
|
||||
// Firefox warns the usage of textures without specifying pixels (#629, #2077)
|
||||
//
|
||||
// Error: WebGL warning: drawElements: This operation requires zeroing texture data. This is slow.
|
||||
//
|
||||
// In Ebitengine, textures are filled with pixels later by the filter that ignores destination, so it is fine
|
||||
// to leave textures as uninitialized here. Rather, extra memory allocating for initialization should be
|
||||
// avoided.
|
||||
//
|
||||
// See also https://stackoverflow.com/questions/57734645.
|
||||
c.ctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, nil)
|
||||
|
||||
return textureNative(t), nil
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixels(buf []byte, f *framebuffer, region image.Rectangle) error {
|
||||
if got, want := len(buf), 4*region.Dx()*region.Dy(); got != want {
|
||||
return fmt.Errorf("opengl: len(buf) must be %d but was %d at framebufferPixels", got, want)
|
||||
}
|
||||
|
||||
c.ctx.Flush()
|
||||
c.bindFramebuffer(f.native)
|
||||
x := int32(region.Min.X)
|
||||
y := int32(region.Min.Y)
|
||||
width := int32(region.Dx())
|
||||
height := int32(region.Dy())
|
||||
c.ctx.ReadPixels(buf, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {
|
||||
c.ctx.Flush()
|
||||
|
||||
c.bindFramebuffer(f.native)
|
||||
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, uint32(buffer))
|
||||
c.ctx.ReadPixels(nil, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
||||
c.ctx.BindBuffer(gl.PIXEL_PACK_BUFFER, 0)
|
||||
}
|
||||
|
||||
func (c *context) deleteTexture(t textureNative) {
|
||||
if c.lastTexture == t {
|
||||
c.lastTexture = 0
|
||||
}
|
||||
c.ctx.DeleteTexture(uint32(t))
|
||||
}
|
||||
|
||||
func (c *context) newRenderbuffer(width, height int) (renderbufferNative, error) {
|
||||
r := c.ctx.CreateRenderbuffer()
|
||||
if r <= 0 {
|
||||
return 0, errors.New("opengl: creating renderbuffer failed")
|
||||
}
|
||||
|
||||
renderbuffer := renderbufferNative(r)
|
||||
c.bindRenderbuffer(renderbuffer)
|
||||
|
||||
var stencilFormat uint32
|
||||
if c.ctx.IsES() {
|
||||
// https://docs.gl/es2/glRenderbufferStorage
|
||||
// > Must be one of the following symbolic constants: GL_RGBA4, GL_RGB565, GL_RGB5_A1,
|
||||
// > GL_DEPTH_COMPONENT16, or GL_STENCIL_INDEX8.
|
||||
//
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/renderbufferStorage
|
||||
// > A GLenum specifying the internal format of the renderbuffer. Possible values:
|
||||
// > * gl.RGBA4: 4 red bits, 4 green bits, 4 blue bits 4 alpha bits.
|
||||
// > * gl.RGB565: 5 red bits, 6 green bits, 5 blue bits.
|
||||
// > * gl.RGB5_A1: 5 red bits, 5 green bits, 5 blue bits, 1 alpha bit.
|
||||
// > * gl.DEPTH_COMPONENT16: 16 depth bits.
|
||||
// > * gl.STENCIL_INDEX8: 8 stencil bits.
|
||||
// > * gl.DEPTH_STENCIL
|
||||
stencilFormat = gl.STENCIL_INDEX8
|
||||
} else {
|
||||
// GL_STENCIL_INDEX8 might not be available with OpenGL 2.1.
|
||||
// https://www.khronos.org/opengl/wiki/Image_Format
|
||||
// > There are only 2 depth/stencil formats, each providing 8 stencil bits: GL_DEPTH24_STENCIL8 and GL_DEPTH32F_STENCIL8.
|
||||
// > [...]
|
||||
// > Stencil formats can only be used for Textures if OpenGL 4.4 or ARB_texture_stencil8 is available.
|
||||
stencilFormat = gl.DEPTH24_STENCIL8
|
||||
}
|
||||
c.ctx.RenderbufferStorage(gl.RENDERBUFFER, stencilFormat, int32(width), int32(height))
|
||||
|
||||
return renderbuffer, nil
|
||||
}
|
||||
|
||||
func (c *context) deleteRenderbuffer(r renderbufferNative) {
|
||||
if !c.ctx.IsRenderbuffer(uint32(r)) {
|
||||
return
|
||||
}
|
||||
if c.lastRenderbuffer == r {
|
||||
c.lastRenderbuffer = 0
|
||||
}
|
||||
c.ctx.DeleteRenderbuffer(uint32(r))
|
||||
}
|
||||
|
||||
func (c *context) newFramebuffer(texture textureNative, width, height int) (*framebuffer, error) {
|
||||
f := c.ctx.CreateFramebuffer()
|
||||
if f <= 0 {
|
||||
return nil, fmt.Errorf("opengl: creating framebuffer failed: the returned value is not positive but %d", f)
|
||||
}
|
||||
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 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,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) error {
|
||||
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))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
if c.lastFramebuffer == f {
|
||||
c.lastFramebuffer = invalidFramebuffer
|
||||
c.lastViewportWidth = 0
|
||||
c.lastViewportHeight = 0
|
||||
}
|
||||
c.ctx.DeleteFramebuffer(uint32(f))
|
||||
}
|
||||
|
||||
func (c *context) newShader(shaderType uint32, source string) (shader, error) {
|
||||
s := c.ctx.CreateShader(shaderType)
|
||||
if s == 0 {
|
||||
return 0, fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (c *context) newProgram(shaders []shader, attributes []string) (program, error) {
|
||||
p := c.ctx.CreateProgram()
|
||||
if p == 0 {
|
||||
return 0, errors.New("opengl: glCreateProgram failed")
|
||||
}
|
||||
|
||||
for _, shader := range shaders {
|
||||
c.ctx.AttachShader(p, uint32(shader))
|
||||
}
|
||||
|
||||
for i, name := range attributes {
|
||||
c.ctx.BindAttribLocation(p, uint32(i), name)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (c *context) deleteProgram(p program) {
|
||||
c.locationCache.deleteProgram(p)
|
||||
|
||||
if !c.ctx.IsProgram(uint32(p)) {
|
||||
return
|
||||
}
|
||||
c.ctx.DeleteProgram(uint32(p))
|
||||
}
|
||||
|
||||
func (c *context) uniformInt(p program, location string, v int) bool {
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
}
|
||||
c.ctx.Uniform1i(int32(l), int32(v))
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) uniforms(p program, location string, v []uint32, typ shaderir.Type) bool {
|
||||
l := c.locationCache.GetUniformLocation(c, p, location)
|
||||
if l == invalidUniform {
|
||||
return false
|
||||
}
|
||||
|
||||
base := typ.Main
|
||||
if base == shaderir.Array {
|
||||
base = typ.Sub[0].Main
|
||||
}
|
||||
|
||||
switch base {
|
||||
case shaderir.Float:
|
||||
c.ctx.Uniform1fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Int:
|
||||
c.ctx.Uniform1iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.Vec2:
|
||||
c.ctx.Uniform2fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec3:
|
||||
c.ctx.Uniform3fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Vec4:
|
||||
c.ctx.Uniform4fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.IVec2:
|
||||
c.ctx.Uniform2iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.IVec3:
|
||||
c.ctx.Uniform3iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.IVec4:
|
||||
c.ctx.Uniform4iv(int32(l), uint32sToInt32s(v))
|
||||
case shaderir.Mat2:
|
||||
c.ctx.UniformMatrix2fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat3:
|
||||
c.ctx.UniformMatrix3fv(int32(l), uint32sToFloat32s(v))
|
||||
case shaderir.Mat4:
|
||||
c.ctx.UniformMatrix4fv(int32(l), uint32sToFloat32s(v))
|
||||
default:
|
||||
panic(fmt.Sprintf("opengl: unexpected type: %s", typ.String()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *context) newArrayBuffer(size int) buffer {
|
||||
b := c.ctx.CreateBuffer()
|
||||
c.ctx.BindBuffer(gl.ARRAY_BUFFER, b)
|
||||
c.ctx.BufferInit(gl.ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
return buffer(b)
|
||||
}
|
||||
|
||||
func (c *context) newElementArrayBuffer(size int) buffer {
|
||||
b := c.ctx.CreateBuffer()
|
||||
c.ctx.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, b)
|
||||
c.ctx.BufferInit(gl.ELEMENT_ARRAY_BUFFER, size, gl.DYNAMIC_DRAW)
|
||||
return buffer(b)
|
||||
}
|
||||
|
||||
func (c *context) glslVersion() glsl.GLSLVersion {
|
||||
if c.ctx.IsES() {
|
||||
return glsl.GLSLVersionES300
|
||||
}
|
||||
return glsl.GLSLVersionDefault
|
||||
}
|
||||
Generated
Vendored
+100
@@ -0,0 +1,100 @@
|
||||
// Copyright 2023 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 nintendosdk
|
||||
|
||||
package opengl
|
||||
|
||||
// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
|
||||
// #cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
|
||||
//
|
||||
// #include <EGL/egl.h>
|
||||
// #include <EGL/eglext.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type egl struct {
|
||||
display C.EGLDisplay
|
||||
surface C.EGLSurface
|
||||
context C.EGLContext
|
||||
}
|
||||
|
||||
func newEGL(nativeWindowHandle uintptr) (*egl, error) {
|
||||
e := &egl{}
|
||||
|
||||
e.display = C.eglGetDisplay(C.NativeDisplayType(C.EGL_DEFAULT_DISPLAY))
|
||||
if e.display == 0 {
|
||||
return nil, fmt.Errorf("opengl: eglGetDisplay failed")
|
||||
}
|
||||
|
||||
if r := C.eglInitialize(e.display, nil, nil); r == 0 {
|
||||
return nil, fmt.Errorf("opengl: eglInitialize failed")
|
||||
}
|
||||
|
||||
configAttribs := []C.EGLint{
|
||||
C.EGL_RENDERABLE_TYPE, C.EGL_OPENGL_BIT,
|
||||
C.EGL_SURFACE_TYPE, C.EGL_WINDOW_BIT,
|
||||
C.EGL_RED_SIZE, 8,
|
||||
C.EGL_GREEN_SIZE, 8,
|
||||
C.EGL_BLUE_SIZE, 8,
|
||||
C.EGL_ALPHA_SIZE, 8,
|
||||
C.EGL_NONE}
|
||||
var numConfigs C.EGLint
|
||||
var config C.EGLConfig
|
||||
if r := C.eglChooseConfig(e.display, &configAttribs[0], &config, 1, &numConfigs); r == 0 {
|
||||
return nil, fmt.Errorf("opengl: eglChooseConfig failed")
|
||||
}
|
||||
if numConfigs != 1 {
|
||||
return nil, fmt.Errorf("opengl: eglChooseConfig failed: numConfigs must be 1 but %d", numConfigs)
|
||||
}
|
||||
|
||||
e.surface = C.eglCreateWindowSurface(e.display, config, C.NativeWindowType(nativeWindowHandle), nil)
|
||||
if e.surface == C.EGLSurface(C.EGL_NO_SURFACE) {
|
||||
return nil, fmt.Errorf("opengl: eglCreateWindowSurface failed")
|
||||
}
|
||||
|
||||
// Set the current rendering API.
|
||||
if r := C.eglBindAPI(C.EGL_OPENGL_API); r == 0 {
|
||||
return nil, fmt.Errorf("opengl: eglBindAPI failed")
|
||||
}
|
||||
|
||||
// Create new context and set it as current.
|
||||
contextAttribs := []C.EGLint{
|
||||
// Set target graphics api version.
|
||||
C.EGL_CONTEXT_MAJOR_VERSION, 3,
|
||||
C.EGL_CONTEXT_MINOR_VERSION, 2,
|
||||
// For debug callback
|
||||
C.EGL_CONTEXT_FLAGS_KHR, C.EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
|
||||
C.EGL_NONE}
|
||||
e.context = C.eglCreateContext(e.display, config, C.EGLContext(C.EGL_NO_CONTEXT), &contextAttribs[0])
|
||||
if e.context == C.EGLContext(C.EGL_NO_CONTEXT) {
|
||||
return nil, fmt.Errorf("opengl: eglCreateContext failed: error: %d", C.eglGetError())
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *egl) makeContextCurrent() error {
|
||||
if r := C.eglMakeCurrent(e.display, e.surface, e.surface, e.context); r == 0 {
|
||||
return fmt.Errorf("opengl: eglMakeCurrent failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *egl) swapBuffers() {
|
||||
C.eglSwapBuffers(e.display, e.surface)
|
||||
}
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
This is a fork of `github.com/go-gl/gl/v2.1/gl` with the below patch. This is now modified manually.
|
||||
|
||||
The original version is generated from `github.com/hajimehoshi/glow`'s `nocgo` branch. This enables to remove dependencies on Cgo on Windows.
|
||||
|
||||
Now we are working on committing this 'no-cgo' change to the official gl package. See https://github.com/go-gl/glow/pull/102.
|
||||
Generated
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
// Copyright 2022 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 gl
|
||||
|
||||
const (
|
||||
ALWAYS = 0x0207
|
||||
ARRAY_BUFFER = 0x8892
|
||||
BACK = 0x0405
|
||||
BLEND = 0x0BE2
|
||||
CLAMP_TO_EDGE = 0x812F
|
||||
COLOR_ATTACHMENT0 = 0x8CE0
|
||||
COMPILE_STATUS = 0x8B81
|
||||
DECR_WRAP = 0x8508
|
||||
DEPTH24_STENCIL8 = 0x88F0
|
||||
DST_ALPHA = 0x0304
|
||||
DST_COLOR = 0x0306
|
||||
DYNAMIC_DRAW = 0x88E8
|
||||
ELEMENT_ARRAY_BUFFER = 0x8893
|
||||
FALSE = 0
|
||||
FLOAT = 0x1406
|
||||
FRAGMENT_SHADER = 0x8B30
|
||||
FRAMEBUFFER = 0x8D40
|
||||
FRAMEBUFFER_BINDING = 0x8CA6
|
||||
FRAMEBUFFER_COMPLETE = 0x8CD5
|
||||
FRONT = 0x0404
|
||||
FRONT_AND_BACK = 0x0408
|
||||
FUNC_ADD = 0x8006
|
||||
FUNC_REVERSE_SUBTRACT = 0x800b
|
||||
FUNC_SUBTRACT = 0x800a
|
||||
HIGH_FLOAT = 0x8DF2
|
||||
INCR_WRAP = 0x8507
|
||||
INFO_LOG_LENGTH = 0x8B84
|
||||
INVERT = 0x150A
|
||||
KEEP = 0x1E00
|
||||
LINK_STATUS = 0x8B82
|
||||
MAX = 0x8008
|
||||
MAX_TEXTURE_SIZE = 0x0D33
|
||||
MIN = 0x8007
|
||||
NEAREST = 0x2600
|
||||
NO_ERROR = 0
|
||||
NOTEQUAL = 0x0205
|
||||
ONE = 1
|
||||
ONE_MINUS_DST_ALPHA = 0x0305
|
||||
ONE_MINUS_DST_COLOR = 0x0307
|
||||
ONE_MINUS_SRC_ALPHA = 0x0303
|
||||
ONE_MINUS_SRC_COLOR = 0x0301
|
||||
PIXEL_PACK_BUFFER = 0x88EB
|
||||
PIXEL_UNPACK_BUFFER = 0x88EC
|
||||
READ_WRITE = 0x88BA
|
||||
RENDERBUFFER = 0x8D41
|
||||
RGBA = 0x1908
|
||||
SCISSOR_TEST = 0x0C11
|
||||
SHORT = 0x1402
|
||||
SRC_ALPHA = 0x0302
|
||||
SRC_ALPHA_SATURATE = 0x0308
|
||||
SRC_COLOR = 0x0300
|
||||
STENCIL_ATTACHMENT = 0x8D20
|
||||
STENCIL_BUFFER_BIT = 0x0400
|
||||
STENCIL_INDEX8 = 0x8D48
|
||||
STENCIL_TEST = 0x0B90
|
||||
STREAM_DRAW = 0x88E0
|
||||
TEXTURE0 = 0x84C0
|
||||
TEXTURE_2D = 0x0DE1
|
||||
TEXTURE_MAG_FILTER = 0x2800
|
||||
TEXTURE_MIN_FILTER = 0x2801
|
||||
TEXTURE_WRAP_S = 0x2802
|
||||
TEXTURE_WRAP_T = 0x2803
|
||||
TRIANGLES = 0x0004
|
||||
TRUE = 1
|
||||
UNPACK_ALIGNMENT = 0x0CF5
|
||||
UNSIGNED_BYTE = 0x1401
|
||||
UNSIGNED_INT = 0x1405
|
||||
VERTEX_SHADER = 0x8B31
|
||||
WRITE_ONLY = 0x88B9
|
||||
ZERO = 0
|
||||
)
|
||||
Generated
Vendored
+647
@@ -0,0 +1,647 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
// Code generated by genkeys.go using 'go generate'. DO NOT EDIT.
|
||||
|
||||
//go:build !playstation5
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type DebugContext struct {
|
||||
Context Context
|
||||
}
|
||||
|
||||
var _ Context = (*DebugContext)(nil)
|
||||
|
||||
func (d *DebugContext) ActiveTexture(arg0 uint32) {
|
||||
d.Context.ActiveTexture(arg0)
|
||||
fmt.Fprintln(os.Stderr, "ActiveTexture")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at ActiveTexture", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) AttachShader(arg0 uint32, arg1 uint32) {
|
||||
d.Context.AttachShader(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "AttachShader")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at AttachShader", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindAttribLocation(arg0 uint32, arg1 uint32, arg2 string) {
|
||||
d.Context.BindAttribLocation(arg0, arg1, arg2)
|
||||
fmt.Fprintln(os.Stderr, "BindAttribLocation")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindAttribLocation", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindBuffer(arg0 uint32, arg1 uint32) {
|
||||
d.Context.BindBuffer(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "BindBuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindBuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindFramebuffer(arg0 uint32, arg1 uint32) {
|
||||
d.Context.BindFramebuffer(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "BindFramebuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindFramebuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindRenderbuffer(arg0 uint32, arg1 uint32) {
|
||||
d.Context.BindRenderbuffer(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "BindRenderbuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindRenderbuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindTexture(arg0 uint32, arg1 uint32) {
|
||||
d.Context.BindTexture(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "BindTexture")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindTexture", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BindVertexArray(arg0 uint32) {
|
||||
d.Context.BindVertexArray(arg0)
|
||||
fmt.Fprintln(os.Stderr, "BindVertexArray")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BindVertexArray", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BlendEquationSeparate(arg0 uint32, arg1 uint32) {
|
||||
d.Context.BlendEquationSeparate(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "BlendEquationSeparate")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BlendEquationSeparate", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BlendFuncSeparate(arg0 uint32, arg1 uint32, arg2 uint32, arg3 uint32) {
|
||||
d.Context.BlendFuncSeparate(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "BlendFuncSeparate")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BlendFuncSeparate", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BufferInit(arg0 uint32, arg1 int, arg2 uint32) {
|
||||
d.Context.BufferInit(arg0, arg1, arg2)
|
||||
fmt.Fprintln(os.Stderr, "BufferInit")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BufferInit", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) BufferSubData(arg0 uint32, arg1 int, arg2 []uint8) {
|
||||
d.Context.BufferSubData(arg0, arg1, arg2)
|
||||
fmt.Fprintln(os.Stderr, "BufferSubData")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at BufferSubData", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) CheckFramebufferStatus(arg0 uint32) uint32 {
|
||||
out0 := d.Context.CheckFramebufferStatus(arg0)
|
||||
fmt.Fprintln(os.Stderr, "CheckFramebufferStatus")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CheckFramebufferStatus", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) Clear(arg0 uint32) {
|
||||
d.Context.Clear(arg0)
|
||||
fmt.Fprintln(os.Stderr, "Clear")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Clear", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) ColorMask(arg0 bool, arg1 bool, arg2 bool, arg3 bool) {
|
||||
d.Context.ColorMask(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "ColorMask")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at ColorMask", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) CompileShader(arg0 uint32) {
|
||||
d.Context.CompileShader(arg0)
|
||||
fmt.Fprintln(os.Stderr, "CompileShader")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CompileShader", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateBuffer() uint32 {
|
||||
out0 := d.Context.CreateBuffer()
|
||||
fmt.Fprintln(os.Stderr, "CreateBuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateBuffer", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateFramebuffer() uint32 {
|
||||
out0 := d.Context.CreateFramebuffer()
|
||||
fmt.Fprintln(os.Stderr, "CreateFramebuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateFramebuffer", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateProgram() uint32 {
|
||||
out0 := d.Context.CreateProgram()
|
||||
fmt.Fprintln(os.Stderr, "CreateProgram")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateProgram", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateRenderbuffer() uint32 {
|
||||
out0 := d.Context.CreateRenderbuffer()
|
||||
fmt.Fprintln(os.Stderr, "CreateRenderbuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateRenderbuffer", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateShader(arg0 uint32) uint32 {
|
||||
out0 := d.Context.CreateShader(arg0)
|
||||
fmt.Fprintln(os.Stderr, "CreateShader")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateShader", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateTexture() uint32 {
|
||||
out0 := d.Context.CreateTexture()
|
||||
fmt.Fprintln(os.Stderr, "CreateTexture")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateTexture", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) CreateVertexArray() uint32 {
|
||||
out0 := d.Context.CreateVertexArray()
|
||||
fmt.Fprintln(os.Stderr, "CreateVertexArray")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at CreateVertexArray", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteBuffer(arg0 uint32) {
|
||||
d.Context.DeleteBuffer(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteBuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteBuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteFramebuffer(arg0 uint32) {
|
||||
d.Context.DeleteFramebuffer(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteFramebuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteFramebuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteProgram(arg0 uint32) {
|
||||
d.Context.DeleteProgram(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteProgram")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteProgram", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteRenderbuffer(arg0 uint32) {
|
||||
d.Context.DeleteRenderbuffer(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteRenderbuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteRenderbuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteShader(arg0 uint32) {
|
||||
d.Context.DeleteShader(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteShader")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteShader", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteTexture(arg0 uint32) {
|
||||
d.Context.DeleteTexture(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteTexture")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteTexture", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DeleteVertexArray(arg0 uint32) {
|
||||
d.Context.DeleteVertexArray(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DeleteVertexArray")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DeleteVertexArray", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Disable(arg0 uint32) {
|
||||
d.Context.Disable(arg0)
|
||||
fmt.Fprintln(os.Stderr, "Disable")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Disable", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DisableVertexAttribArray(arg0 uint32) {
|
||||
d.Context.DisableVertexAttribArray(arg0)
|
||||
fmt.Fprintln(os.Stderr, "DisableVertexAttribArray")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DisableVertexAttribArray", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) DrawElements(arg0 uint32, arg1 int32, arg2 uint32, arg3 int) {
|
||||
d.Context.DrawElements(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "DrawElements")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at DrawElements", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Enable(arg0 uint32) {
|
||||
d.Context.Enable(arg0)
|
||||
fmt.Fprintln(os.Stderr, "Enable")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Enable", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) EnableVertexAttribArray(arg0 uint32) {
|
||||
d.Context.EnableVertexAttribArray(arg0)
|
||||
fmt.Fprintln(os.Stderr, "EnableVertexAttribArray")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at EnableVertexAttribArray", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Flush() {
|
||||
d.Context.Flush()
|
||||
fmt.Fprintln(os.Stderr, "Flush")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Flush", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) FramebufferRenderbuffer(arg0 uint32, arg1 uint32, arg2 uint32, arg3 uint32) {
|
||||
d.Context.FramebufferRenderbuffer(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "FramebufferRenderbuffer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at FramebufferRenderbuffer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) FramebufferTexture2D(arg0 uint32, arg1 uint32, arg2 uint32, arg3 uint32, arg4 int32) {
|
||||
d.Context.FramebufferTexture2D(arg0, arg1, arg2, arg3, arg4)
|
||||
fmt.Fprintln(os.Stderr, "FramebufferTexture2D")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at FramebufferTexture2D", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetError() uint32 {
|
||||
out0 := d.Context.GetError()
|
||||
fmt.Fprintln(os.Stderr, "GetError")
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetInteger(arg0 uint32) int {
|
||||
out0 := d.Context.GetInteger(arg0)
|
||||
fmt.Fprintln(os.Stderr, "GetInteger")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetInteger", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetProgramInfoLog(arg0 uint32) string {
|
||||
out0 := d.Context.GetProgramInfoLog(arg0)
|
||||
fmt.Fprintln(os.Stderr, "GetProgramInfoLog")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetProgramInfoLog", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetProgrami(arg0 uint32, arg1 uint32) int {
|
||||
out0 := d.Context.GetProgrami(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "GetProgrami")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetProgrami", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetShaderInfoLog(arg0 uint32) string {
|
||||
out0 := d.Context.GetShaderInfoLog(arg0)
|
||||
fmt.Fprintln(os.Stderr, "GetShaderInfoLog")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetShaderInfoLog", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetShaderi(arg0 uint32, arg1 uint32) int {
|
||||
out0 := d.Context.GetShaderi(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "GetShaderi")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetShaderi", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) GetUniformLocation(arg0 uint32, arg1 string) int32 {
|
||||
out0 := d.Context.GetUniformLocation(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "GetUniformLocation")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at GetUniformLocation", e))
|
||||
}
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) IsES() bool {
|
||||
out0 := d.Context.IsES()
|
||||
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")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at IsProgram", e))
|
||||
}
|
||||
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")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at LinkProgram", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) LoadFunctions() error {
|
||||
out0 := d.Context.LoadFunctions()
|
||||
return out0
|
||||
}
|
||||
|
||||
func (d *DebugContext) PixelStorei(arg0 uint32, arg1 int32) {
|
||||
d.Context.PixelStorei(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "PixelStorei")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at PixelStorei", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) ReadPixels(arg0 []uint8, arg1 int32, arg2 int32, arg3 int32, arg4 int32, arg5 uint32, arg6 uint32) {
|
||||
d.Context.ReadPixels(arg0, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
fmt.Fprintln(os.Stderr, "ReadPixels")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at ReadPixels", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) RenderbufferStorage(arg0 uint32, arg1 uint32, arg2 int32, arg3 int32) {
|
||||
d.Context.RenderbufferStorage(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "RenderbufferStorage")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at RenderbufferStorage", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Scissor(arg0 int32, arg1 int32, arg2 int32, arg3 int32) {
|
||||
d.Context.Scissor(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "Scissor")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Scissor", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) ShaderSource(arg0 uint32, arg1 string) {
|
||||
d.Context.ShaderSource(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "ShaderSource")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at ShaderSource", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) StencilFunc(arg0 uint32, arg1 int32, arg2 uint32) {
|
||||
d.Context.StencilFunc(arg0, arg1, arg2)
|
||||
fmt.Fprintln(os.Stderr, "StencilFunc")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at StencilFunc", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) StencilOpSeparate(arg0 uint32, arg1 uint32, arg2 uint32, arg3 uint32) {
|
||||
d.Context.StencilOpSeparate(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "StencilOpSeparate")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at StencilOpSeparate", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) TexImage2D(arg0 uint32, arg1 int32, arg2 int32, arg3 int32, arg4 int32, arg5 uint32, arg6 uint32, arg7 []uint8) {
|
||||
d.Context.TexImage2D(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||
fmt.Fprintln(os.Stderr, "TexImage2D")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at TexImage2D", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) TexParameteri(arg0 uint32, arg1 uint32, arg2 int32) {
|
||||
d.Context.TexParameteri(arg0, arg1, arg2)
|
||||
fmt.Fprintln(os.Stderr, "TexParameteri")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at TexParameteri", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) TexSubImage2D(arg0 uint32, arg1 int32, arg2 int32, arg3 int32, arg4 int32, arg5 int32, arg6 uint32, arg7 uint32, arg8 []uint8) {
|
||||
d.Context.TexSubImage2D(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||
fmt.Fprintln(os.Stderr, "TexSubImage2D")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at TexSubImage2D", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform1fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.Uniform1fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform1fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform1fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform1i(arg0 int32, arg1 int32) {
|
||||
d.Context.Uniform1i(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform1i")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform1i", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform1iv(arg0 int32, arg1 []int32) {
|
||||
d.Context.Uniform1iv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform1iv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform1iv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform2fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.Uniform2fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform2fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform2fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform2iv(arg0 int32, arg1 []int32) {
|
||||
d.Context.Uniform2iv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform2iv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform2iv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform3fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.Uniform3fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform3fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform3fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform3iv(arg0 int32, arg1 []int32) {
|
||||
d.Context.Uniform3iv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform3iv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform3iv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform4fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.Uniform4fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform4fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform4fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Uniform4iv(arg0 int32, arg1 []int32) {
|
||||
d.Context.Uniform4iv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "Uniform4iv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Uniform4iv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) UniformMatrix2fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.UniformMatrix2fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "UniformMatrix2fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at UniformMatrix2fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) UniformMatrix3fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.UniformMatrix3fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "UniformMatrix3fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at UniformMatrix3fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) UniformMatrix4fv(arg0 int32, arg1 []float32) {
|
||||
d.Context.UniformMatrix4fv(arg0, arg1)
|
||||
fmt.Fprintln(os.Stderr, "UniformMatrix4fv")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at UniformMatrix4fv", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) UseProgram(arg0 uint32) {
|
||||
d.Context.UseProgram(arg0)
|
||||
fmt.Fprintln(os.Stderr, "UseProgram")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at UseProgram", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) VertexAttribPointer(arg0 uint32, arg1 int32, arg2 uint32, arg3 bool, arg4 int32, arg5 int) {
|
||||
d.Context.VertexAttribPointer(arg0, arg1, arg2, arg3, arg4, arg5)
|
||||
fmt.Fprintln(os.Stderr, "VertexAttribPointer")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at VertexAttribPointer", e))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DebugContext) Viewport(arg0 int32, arg1 int32, arg2 int32, arg3 int32) {
|
||||
d.Context.Viewport(arg0, arg1, arg2, arg3)
|
||||
fmt.Fprintln(os.Stderr, "Viewport")
|
||||
if e := d.Context.GetError(); e != NO_ERROR {
|
||||
panic(fmt.Sprintf("gl: GetError() returned %d at Viewport", e))
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+853
@@ -0,0 +1,853 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2014 Eric Woroshow
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build !darwin && !js && !windows && !playstation5
|
||||
|
||||
package gl
|
||||
|
||||
// #include <stdint.h>
|
||||
// #include <stdlib.h>
|
||||
//
|
||||
// typedef unsigned int GLenum;
|
||||
// typedef unsigned char GLboolean;
|
||||
// typedef unsigned int GLbitfield;
|
||||
// typedef int GLint;
|
||||
// typedef unsigned int GLuint;
|
||||
// typedef int GLsizei;
|
||||
// typedef float GLfloat;
|
||||
// typedef char GLchar;
|
||||
// typedef ptrdiff_t GLintptr;
|
||||
// typedef ptrdiff_t GLsizeiptr;
|
||||
//
|
||||
// static void glowActiveTexture(uintptr_t fnptr, GLenum texture) {
|
||||
// typedef void (*fn)(GLenum texture);
|
||||
// ((fn)(fnptr))(texture);
|
||||
// }
|
||||
// static void glowAttachShader(uintptr_t fnptr, GLuint program, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint program, GLuint shader);
|
||||
// ((fn)(fnptr))(program, shader);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowBindBuffer(uintptr_t fnptr, GLenum target, GLuint buffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint buffer);
|
||||
// ((fn)(fnptr))(target, buffer);
|
||||
// }
|
||||
// static void glowBindFramebuffer(uintptr_t fnptr, GLenum target, GLuint framebuffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint framebuffer);
|
||||
// ((fn)(fnptr))(target, framebuffer);
|
||||
// }
|
||||
// static void glowBindRenderbuffer(uintptr_t fnptr, GLenum target, GLuint renderbuffer) {
|
||||
// typedef void (*fn)(GLenum target, GLuint renderbuffer);
|
||||
// ((fn)(fnptr))(target, renderbuffer);
|
||||
// }
|
||||
// static void glowBindTexture(uintptr_t fnptr, GLenum target, GLuint texture) {
|
||||
// typedef void (*fn)(GLenum target, GLuint texture);
|
||||
// ((fn)(fnptr))(target, texture);
|
||||
// }
|
||||
// static void glowBindVertexArray(uintptr_t fnptr, GLuint array) {
|
||||
// typedef void (*fn)(GLuint array);
|
||||
// ((fn)(fnptr))(array);
|
||||
// }
|
||||
// static void glowBlendEquationSeparate(uintptr_t fnptr, GLenum modeRGB, GLenum modeAlpha) {
|
||||
// typedef void (*fn)(GLenum modeRGB, GLenum modeAlpha);
|
||||
// ((fn)(fnptr))(modeRGB, modeAlpha);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static GLenum glowCheckFramebufferStatus(uintptr_t fnptr, GLenum target) {
|
||||
// typedef GLenum (*fn)(GLenum target);
|
||||
// return ((fn)(fnptr))(target);
|
||||
// }
|
||||
// static void glowClear(uintptr_t fnptr, GLbitfield mask) {
|
||||
// typedef void (*fn)(GLbitfield mask);
|
||||
// ((fn)(fnptr))(mask);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowCompileShader(uintptr_t fnptr, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint shader);
|
||||
// ((fn)(fnptr))(shader);
|
||||
// }
|
||||
// static GLuint glowCreateProgram(uintptr_t fnptr) {
|
||||
// typedef GLuint (*fn)();
|
||||
// return ((fn)(fnptr))();
|
||||
// }
|
||||
// static GLuint glowCreateShader(uintptr_t fnptr, GLenum type) {
|
||||
// typedef GLuint (*fn)(GLenum type);
|
||||
// return ((fn)(fnptr))(type);
|
||||
// }
|
||||
// static void glowDeleteBuffers(uintptr_t fnptr, GLsizei n, const GLuint* buffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* buffers);
|
||||
// ((fn)(fnptr))(n, buffers);
|
||||
// }
|
||||
// static void glowDeleteFramebuffers(uintptr_t fnptr, GLsizei n, const GLuint* framebuffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* framebuffers);
|
||||
// ((fn)(fnptr))(n, framebuffers);
|
||||
// }
|
||||
// static void glowDeleteProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
// static void glowDeleteRenderbuffers(uintptr_t fnptr, GLsizei n, const GLuint* renderbuffers) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* renderbuffers);
|
||||
// ((fn)(fnptr))(n, renderbuffers);
|
||||
// }
|
||||
// static void glowDeleteShader(uintptr_t fnptr, GLuint shader) {
|
||||
// typedef void (*fn)(GLuint shader);
|
||||
// ((fn)(fnptr))(shader);
|
||||
// }
|
||||
// static void glowDeleteTextures(uintptr_t fnptr, GLsizei n, const GLuint* textures) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* textures);
|
||||
// ((fn)(fnptr))(n, textures);
|
||||
// }
|
||||
// static void glowDeleteVertexArrays(uintptr_t fnptr, GLsizei n, const GLuint* arrays) {
|
||||
// typedef void (*fn)(GLsizei n, const GLuint* arrays);
|
||||
// ((fn)(fnptr))(n, arrays);
|
||||
// }
|
||||
// static void glowDisable(uintptr_t fnptr, GLenum cap) {
|
||||
// typedef void (*fn)(GLenum cap);
|
||||
// ((fn)(fnptr))(cap);
|
||||
// }
|
||||
// static void glowDisableVertexAttribArray(uintptr_t fnptr, GLuint index) {
|
||||
// typedef void (*fn)(GLuint index);
|
||||
// ((fn)(fnptr))(index);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowEnable(uintptr_t fnptr, GLenum cap) {
|
||||
// typedef void (*fn)(GLenum cap);
|
||||
// ((fn)(fnptr))(cap);
|
||||
// }
|
||||
// static void glowEnableVertexAttribArray(uintptr_t fnptr, GLuint index) {
|
||||
// typedef void (*fn)(GLuint index);
|
||||
// ((fn)(fnptr))(index);
|
||||
// }
|
||||
// static void glowFlush(uintptr_t fnptr) {
|
||||
// typedef void (*fn)();
|
||||
// ((fn)(fnptr))();
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowGenBuffers(uintptr_t fnptr, GLsizei n, GLuint* buffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* buffers);
|
||||
// ((fn)(fnptr))(n, buffers);
|
||||
// }
|
||||
// static void glowGenFramebuffers(uintptr_t fnptr, GLsizei n, GLuint* framebuffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* framebuffers);
|
||||
// ((fn)(fnptr))(n, framebuffers);
|
||||
// }
|
||||
// static void glowGenRenderbuffers(uintptr_t fnptr, GLsizei n, GLuint* renderbuffers) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* renderbuffers);
|
||||
// ((fn)(fnptr))(n, renderbuffers);
|
||||
// }
|
||||
// static void glowGenTextures(uintptr_t fnptr, GLsizei n, GLuint* textures) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* textures);
|
||||
// ((fn)(fnptr))(n, textures);
|
||||
// }
|
||||
// static void glowGenVertexArrays(uintptr_t fnptr, GLsizei n, GLuint* arrays) {
|
||||
// typedef void (*fn)(GLsizei n, GLuint* arrays);
|
||||
// ((fn)(fnptr))(n, arrays);
|
||||
// }
|
||||
// static GLenum glowGetError(uintptr_t fnptr) {
|
||||
// typedef GLenum (*fn)();
|
||||
// return ((fn)(fnptr))();
|
||||
// }
|
||||
// static void glowGetIntegerv(uintptr_t fnptr, GLenum pname, GLint* data) {
|
||||
// typedef void (*fn)(GLenum pname, GLint* data);
|
||||
// ((fn)(fnptr))(pname, data);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowLinkProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
// static void glowPixelStorei(uintptr_t fnptr, GLenum pname, GLint param) {
|
||||
// typedef void (*fn)(GLenum pname, GLint param);
|
||||
// ((fn)(fnptr))(pname, param);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowUniform1i(uintptr_t fnptr, GLint location, GLint v0) {
|
||||
// typedef void (*fn)(GLint location, GLint v0);
|
||||
// ((fn)(fnptr))(location, v0);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// static void glowUseProgram(uintptr_t fnptr, GLuint program) {
|
||||
// typedef void (*fn)(GLuint program);
|
||||
// ((fn)(fnptr))(program);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
// 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);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type defaultContext struct {
|
||||
gpActiveTexture C.uintptr_t
|
||||
gpAttachShader C.uintptr_t
|
||||
gpBindAttribLocation C.uintptr_t
|
||||
gpBindBuffer C.uintptr_t
|
||||
gpBindFramebuffer C.uintptr_t
|
||||
gpBindRenderbuffer C.uintptr_t
|
||||
gpBindTexture C.uintptr_t
|
||||
gpBindVertexArray C.uintptr_t
|
||||
gpBlendEquationSeparate C.uintptr_t
|
||||
gpBlendFuncSeparate C.uintptr_t
|
||||
gpBufferData C.uintptr_t
|
||||
gpBufferSubData C.uintptr_t
|
||||
gpCheckFramebufferStatus C.uintptr_t
|
||||
gpClear C.uintptr_t
|
||||
gpColorMask C.uintptr_t
|
||||
gpCompileShader C.uintptr_t
|
||||
gpCreateProgram C.uintptr_t
|
||||
gpCreateShader C.uintptr_t
|
||||
gpDeleteBuffers C.uintptr_t
|
||||
gpDeleteFramebuffers C.uintptr_t
|
||||
gpDeleteProgram C.uintptr_t
|
||||
gpDeleteRenderbuffers C.uintptr_t
|
||||
gpDeleteShader C.uintptr_t
|
||||
gpDeleteTextures C.uintptr_t
|
||||
gpDeleteVertexArrays C.uintptr_t
|
||||
gpDisable C.uintptr_t
|
||||
gpDisableVertexAttribArray C.uintptr_t
|
||||
gpDrawElements C.uintptr_t
|
||||
gpEnable C.uintptr_t
|
||||
gpEnableVertexAttribArray C.uintptr_t
|
||||
gpFlush C.uintptr_t
|
||||
gpFramebufferRenderbuffer C.uintptr_t
|
||||
gpFramebufferTexture2D C.uintptr_t
|
||||
gpGenBuffers C.uintptr_t
|
||||
gpGenFramebuffers C.uintptr_t
|
||||
gpGenRenderbuffers C.uintptr_t
|
||||
gpGenTextures C.uintptr_t
|
||||
gpGenVertexArrays C.uintptr_t
|
||||
gpGetError C.uintptr_t
|
||||
gpGetIntegerv C.uintptr_t
|
||||
gpGetProgramInfoLog C.uintptr_t
|
||||
gpGetProgramiv C.uintptr_t
|
||||
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
|
||||
gpRenderbufferStorage C.uintptr_t
|
||||
gpScissor C.uintptr_t
|
||||
gpShaderSource C.uintptr_t
|
||||
gpStencilFunc C.uintptr_t
|
||||
gpStencilOpSeparate C.uintptr_t
|
||||
gpTexImage2D C.uintptr_t
|
||||
gpTexParameteri C.uintptr_t
|
||||
gpTexSubImage2D C.uintptr_t
|
||||
gpUniform1fv C.uintptr_t
|
||||
gpUniform1i C.uintptr_t
|
||||
gpUniform1iv C.uintptr_t
|
||||
gpUniform2fv C.uintptr_t
|
||||
gpUniform2iv C.uintptr_t
|
||||
gpUniform3fv C.uintptr_t
|
||||
gpUniform3iv C.uintptr_t
|
||||
gpUniform4fv C.uintptr_t
|
||||
gpUniform4iv C.uintptr_t
|
||||
gpUniformMatrix2fv C.uintptr_t
|
||||
gpUniformMatrix3fv C.uintptr_t
|
||||
gpUniformMatrix4fv C.uintptr_t
|
||||
gpUseProgram C.uintptr_t
|
||||
gpVertexAttribPointer C.uintptr_t
|
||||
gpViewport C.uintptr_t
|
||||
|
||||
isES bool
|
||||
}
|
||||
|
||||
func NewDefaultContext() (Context, error) {
|
||||
ctx := &defaultContext{}
|
||||
if err := ctx.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsES() bool {
|
||||
return c.isES
|
||||
}
|
||||
|
||||
func (c *defaultContext) ActiveTexture(texture uint32) {
|
||||
C.glowActiveTexture(c.gpActiveTexture, C.GLenum(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) AttachShader(program uint32, shader uint32) {
|
||||
C.glowAttachShader(c.gpAttachShader, C.GLuint(program), C.GLuint(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
C.glowBindAttribLocation(c.gpBindAttribLocation, C.GLuint(program), C.GLuint(index), (*C.GLchar)(unsafe.Pointer(cname)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindBuffer(target uint32, buffer uint32) {
|
||||
C.glowBindBuffer(c.gpBindBuffer, C.GLenum(target), C.GLuint(buffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindFramebuffer(target uint32, framebuffer uint32) {
|
||||
C.glowBindFramebuffer(c.gpBindFramebuffer, C.GLenum(target), C.GLuint(framebuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindRenderbuffer(target uint32, renderbuffer uint32) {
|
||||
C.glowBindRenderbuffer(c.gpBindRenderbuffer, C.GLenum(target), C.GLuint(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindTexture(target uint32, texture uint32) {
|
||||
C.glowBindTexture(c.gpBindTexture, C.GLenum(target), C.GLuint(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindVertexArray(array uint32) {
|
||||
C.glowBindVertexArray(c.gpBindVertexArray, C.GLuint(array))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
C.glowBlendEquationSeparate(c.gpBlendEquationSeparate, C.GLenum(modeRGB), C.GLenum(modeAlpha))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
C.glowBlendFuncSeparate(c.gpBlendFuncSeparate, C.GLenum(srcRGB), C.GLenum(dstRGB), C.GLenum(srcAlpha), C.GLenum(dstAlpha))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferInit(target uint32, size int, usage uint32) {
|
||||
C.glowBufferData(c.gpBufferData, C.GLenum(target), C.GLsizeiptr(size), nil, C.GLenum(usage))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferSubData(target uint32, offset int, data []byte) {
|
||||
C.glowBufferSubData(c.gpBufferSubData, C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(len(data)), unsafe.Pointer(&data[0]))
|
||||
runtime.KeepAlive(data)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CheckFramebufferStatus(target uint32) uint32 {
|
||||
ret := C.glowCheckFramebufferStatus(c.gpCheckFramebufferStatus, C.GLenum(target))
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Clear(mask uint32) {
|
||||
C.glowClear(c.gpClear, C.GLbitfield(mask))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ColorMask(red bool, green bool, blue bool, alpha bool) {
|
||||
C.glowColorMask(c.gpColorMask, C.GLboolean(boolToInt(red)), C.GLboolean(boolToInt(green)), C.GLboolean(boolToInt(blue)), C.GLboolean(boolToInt(alpha)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CompileShader(shader uint32) {
|
||||
C.glowCompileShader(c.gpCompileShader, C.GLuint(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateBuffer() uint32 {
|
||||
var buffer uint32
|
||||
C.glowGenBuffers(c.gpGenBuffers, 1, (*C.GLuint)(unsafe.Pointer(&buffer)))
|
||||
return buffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateFramebuffer() uint32 {
|
||||
var framebuffer uint32
|
||||
C.glowGenFramebuffers(c.gpGenFramebuffers, 1, (*C.GLuint)(unsafe.Pointer(&framebuffer)))
|
||||
return framebuffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateProgram() uint32 {
|
||||
ret := C.glowCreateProgram(c.gpCreateProgram)
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateRenderbuffer() uint32 {
|
||||
var renderbuffer uint32
|
||||
C.glowGenRenderbuffers(c.gpGenRenderbuffers, 1, (*C.GLuint)(unsafe.Pointer(&renderbuffer)))
|
||||
return renderbuffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateShader(xtype uint32) uint32 {
|
||||
ret := C.glowCreateShader(c.gpCreateShader, C.GLenum(xtype))
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateTexture() uint32 {
|
||||
var texture uint32
|
||||
C.glowGenTextures(c.gpGenTextures, 1, (*C.GLuint)(unsafe.Pointer(&texture)))
|
||||
return texture
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateVertexArray() uint32 {
|
||||
var array uint32
|
||||
C.glowGenVertexArrays(c.gpGenVertexArrays, 1, (*C.GLuint)(unsafe.Pointer(&array)))
|
||||
return array
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteBuffer(buffer uint32) {
|
||||
C.glowDeleteBuffers(c.gpDeleteBuffers, 1, (*C.GLuint)(unsafe.Pointer(&buffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteFramebuffer(framebuffer uint32) {
|
||||
C.glowDeleteFramebuffers(c.gpDeleteFramebuffers, 1, (*C.GLuint)(unsafe.Pointer(&framebuffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteProgram(program uint32) {
|
||||
C.glowDeleteProgram(c.gpDeleteProgram, C.GLuint(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteRenderbuffer(renderbuffer uint32) {
|
||||
C.glowDeleteRenderbuffers(c.gpDeleteRenderbuffers, 1, (*C.GLuint)(unsafe.Pointer(&renderbuffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteShader(shader uint32) {
|
||||
C.glowDeleteShader(c.gpDeleteShader, C.GLuint(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteTexture(texture uint32) {
|
||||
C.glowDeleteTextures(c.gpDeleteTextures, 1, (*C.GLuint)(unsafe.Pointer(&texture)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteVertexArray(array uint32) {
|
||||
C.glowDeleteVertexArrays(c.gpDeleteVertexArrays, 1, (*C.GLuint)(unsafe.Pointer(&array)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Disable(cap uint32) {
|
||||
C.glowDisable(c.gpDisable, C.GLenum(cap))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DisableVertexAttribArray(index uint32) {
|
||||
C.glowDisableVertexAttribArray(c.gpDisableVertexAttribArray, C.GLuint(index))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
|
||||
C.glowDrawElements(c.gpDrawElements, C.GLenum(mode), C.GLsizei(count), C.GLenum(xtype), C.uintptr_t(offset))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Enable(cap uint32) {
|
||||
C.glowEnable(c.gpEnable, C.GLenum(cap))
|
||||
}
|
||||
|
||||
func (c *defaultContext) EnableVertexAttribArray(index uint32) {
|
||||
C.glowEnableVertexAttribArray(c.gpEnableVertexAttribArray, C.GLuint(index))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Flush() {
|
||||
C.glowFlush(c.gpFlush)
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
C.glowFramebufferRenderbuffer(c.gpFramebufferRenderbuffer, C.GLenum(target), C.GLenum(attachment), C.GLenum(renderbuffertarget), C.GLuint(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
|
||||
C.glowFramebufferTexture2D(c.gpFramebufferTexture2D, C.GLenum(target), C.GLenum(attachment), C.GLenum(textarget), C.GLuint(texture), C.GLint(level))
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetError() uint32 {
|
||||
ret := C.glowGetError(c.gpGetError)
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
var dst int32
|
||||
C.glowGetIntegerv(c.gpGetIntegerv, C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
|
||||
infoLog := make([]byte, bufSize)
|
||||
C.glowGetProgramInfoLog(c.gpGetProgramInfoLog, C.GLuint(program), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
var dst int32
|
||||
C.glowGetProgramiv(c.gpGetProgramiv, C.GLuint(program), C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
|
||||
infoLog := make([]byte, bufSize)
|
||||
C.glowGetShaderInfoLog(c.gpGetShaderInfoLog, C.GLuint(shader), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderi(shader uint32, pname uint32) int {
|
||||
var dst int32
|
||||
C.glowGetShaderiv(c.gpGetShaderiv, C.GLuint(shader), C.GLenum(pname), (*C.GLint)(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
ret := C.glowGetUniformLocation(c.gpGetUniformLocation, C.GLuint(program), (*C.GLchar)(unsafe.Pointer(cname)))
|
||||
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))
|
||||
}
|
||||
|
||||
func (c *defaultContext) PixelStorei(pname uint32, param int32) {
|
||||
C.glowPixelStorei(c.gpPixelStorei, C.GLenum(pname), C.GLint(param))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
|
||||
C.glowReadPixels(c.gpReadPixels, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(&dst[0]))
|
||||
}
|
||||
|
||||
func (c *defaultContext) RenderbufferStorage(target uint32, internalformat uint32, width int32, height int32) {
|
||||
C.glowRenderbufferStorage(c.gpRenderbufferStorage, C.GLenum(target), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Scissor(x int32, y int32, width int32, height int32) {
|
||||
C.glowScissor(c.gpScissor, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ShaderSource(shader uint32, xstring string) {
|
||||
cstring := C.CString(xstring)
|
||||
defer C.free(unsafe.Pointer(cstring))
|
||||
C.glowShaderSource(c.gpShaderSource, C.GLuint(shader), 1, (**C.GLchar)(unsafe.Pointer(&cstring)), nil)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilFunc(xfunc uint32, ref int32, mask uint32) {
|
||||
C.glowStencilFunc(c.gpStencilFunc, C.GLenum(xfunc), C.GLint(ref), C.GLuint(mask))
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilOpSeparate(face uint32, fail uint32, zfail uint32, zpass uint32) {
|
||||
C.glowStencilOpSeparate(c.gpStencilOpSeparate, C.GLenum(face), C.GLenum(fail), C.GLenum(zfail), C.GLenum(zpass))
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
var ptr *byte
|
||||
if len(pixels) > 0 {
|
||||
ptr = &pixels[0]
|
||||
}
|
||||
C.glowTexImage2D(c.gpTexImage2D, C.GLenum(target), C.GLint(level), C.GLint(internalformat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(ptr))
|
||||
runtime.KeepAlive(pixels)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
C.glowTexParameteri(c.gpTexParameteri, C.GLenum(target), C.GLenum(pname), C.GLint(param))
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
C.glowTexSubImage2D(c.gpTexSubImage2D, C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(xtype), unsafe.Pointer(&pixels[0]))
|
||||
runtime.KeepAlive(pixels)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1fv(location int32, value []float32) {
|
||||
C.glowUniform1fv(c.gpUniform1fv, C.GLint(location), C.GLsizei(len(value)), (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1i(location int32, v0 int32) {
|
||||
C.glowUniform1i(c.gpUniform1i, C.GLint(location), C.GLint(v0))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1iv(location int32, value []int32) {
|
||||
C.glowUniform1iv(c.gpUniform1iv, C.GLint(location), C.GLsizei(len(value)), (*C.GLint)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2fv(location int32, value []float32) {
|
||||
C.glowUniform2fv(c.gpUniform2fv, C.GLint(location), C.GLsizei(len(value)/2), (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
|
||||
C.glowUniform2iv(c.gpUniform2iv, C.GLint(location), C.GLsizei(len(value)/2), (*C.GLint)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
|
||||
C.glowUniform3fv(c.gpUniform3fv, C.GLint(location), C.GLsizei(len(value)/3), (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
|
||||
C.glowUniform3iv(c.gpUniform3iv, C.GLint(location), C.GLsizei(len(value)/3), (*C.GLint)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
|
||||
C.glowUniform4fv(c.gpUniform4fv, C.GLint(location), C.GLsizei(len(value)/4), (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
|
||||
C.glowUniform4iv(c.gpUniform4iv, C.GLint(location), C.GLsizei(len(value)/4), (*C.GLint)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
|
||||
C.glowUniformMatrix2fv(c.gpUniformMatrix2fv, C.GLint(location), C.GLsizei(len(value)/4), 0, (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix3fv(location int32, value []float32) {
|
||||
C.glowUniformMatrix3fv(c.gpUniformMatrix3fv, C.GLint(location), C.GLsizei(len(value)/9), 0, (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix4fv(location int32, value []float32) {
|
||||
C.glowUniformMatrix4fv(c.gpUniformMatrix4fv, C.GLint(location), C.GLsizei(len(value)/16), 0, (*C.GLfloat)(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UseProgram(program uint32) {
|
||||
C.glowUseProgram(c.gpUseProgram, C.GLuint(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
|
||||
C.glowVertexAttribPointer(c.gpVertexAttribPointer, C.GLuint(index), C.GLint(size), C.GLenum(xtype), C.GLboolean(boolToInt(normalized)), C.GLsizei(stride), C.uintptr_t(offset))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Viewport(x int32, y int32, width int32, height int32) {
|
||||
C.glowViewport(c.gpViewport, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) LoadFunctions() error {
|
||||
g := procAddressGetter{ctx: c}
|
||||
|
||||
c.gpActiveTexture = C.uintptr_t(g.get("glActiveTexture"))
|
||||
c.gpAttachShader = C.uintptr_t(g.get("glAttachShader"))
|
||||
c.gpBindAttribLocation = C.uintptr_t(g.get("glBindAttribLocation"))
|
||||
c.gpBindBuffer = C.uintptr_t(g.get("glBindBuffer"))
|
||||
c.gpBindFramebuffer = C.uintptr_t(g.get("glBindFramebuffer"))
|
||||
c.gpBindRenderbuffer = C.uintptr_t(g.get("glBindRenderbuffer"))
|
||||
c.gpBindTexture = C.uintptr_t(g.get("glBindTexture"))
|
||||
c.gpBindVertexArray = C.uintptr_t(g.get("glBindVertexArray"))
|
||||
c.gpBlendEquationSeparate = C.uintptr_t(g.get("glBlendEquationSeparate"))
|
||||
c.gpBlendFuncSeparate = C.uintptr_t(g.get("glBlendFuncSeparate"))
|
||||
c.gpBufferData = C.uintptr_t(g.get("glBufferData"))
|
||||
c.gpBufferSubData = C.uintptr_t(g.get("glBufferSubData"))
|
||||
c.gpCheckFramebufferStatus = C.uintptr_t(g.get("glCheckFramebufferStatus"))
|
||||
c.gpClear = C.uintptr_t(g.get("glClear"))
|
||||
c.gpColorMask = C.uintptr_t(g.get("glColorMask"))
|
||||
c.gpCompileShader = C.uintptr_t(g.get("glCompileShader"))
|
||||
c.gpCreateProgram = C.uintptr_t(g.get("glCreateProgram"))
|
||||
c.gpCreateShader = C.uintptr_t(g.get("glCreateShader"))
|
||||
c.gpDeleteBuffers = C.uintptr_t(g.get("glDeleteBuffers"))
|
||||
c.gpDeleteFramebuffers = C.uintptr_t(g.get("glDeleteFramebuffers"))
|
||||
c.gpDeleteProgram = C.uintptr_t(g.get("glDeleteProgram"))
|
||||
c.gpDeleteRenderbuffers = C.uintptr_t(g.get("glDeleteRenderbuffers"))
|
||||
c.gpDeleteShader = C.uintptr_t(g.get("glDeleteShader"))
|
||||
c.gpDeleteTextures = C.uintptr_t(g.get("glDeleteTextures"))
|
||||
c.gpDeleteVertexArrays = C.uintptr_t(g.get("glDeleteVertexArrays"))
|
||||
c.gpDisable = C.uintptr_t(g.get("glDisable"))
|
||||
c.gpDisableVertexAttribArray = C.uintptr_t(g.get("glDisableVertexAttribArray"))
|
||||
c.gpDrawElements = C.uintptr_t(g.get("glDrawElements"))
|
||||
c.gpEnable = C.uintptr_t(g.get("glEnable"))
|
||||
c.gpEnableVertexAttribArray = C.uintptr_t(g.get("glEnableVertexAttribArray"))
|
||||
c.gpFlush = C.uintptr_t(g.get("glFlush"))
|
||||
c.gpFramebufferRenderbuffer = C.uintptr_t(g.get("glFramebufferRenderbuffer"))
|
||||
c.gpFramebufferTexture2D = C.uintptr_t(g.get("glFramebufferTexture2D"))
|
||||
c.gpGenBuffers = C.uintptr_t(g.get("glGenBuffers"))
|
||||
c.gpGenFramebuffers = C.uintptr_t(g.get("glGenFramebuffers"))
|
||||
c.gpGenRenderbuffers = C.uintptr_t(g.get("glGenRenderbuffers"))
|
||||
c.gpGenTextures = C.uintptr_t(g.get("glGenTextures"))
|
||||
c.gpGenVertexArrays = C.uintptr_t(g.get("glGenVertexArrays"))
|
||||
c.gpGetError = C.uintptr_t(g.get("glGetError"))
|
||||
c.gpGetIntegerv = C.uintptr_t(g.get("glGetIntegerv"))
|
||||
c.gpGetProgramInfoLog = C.uintptr_t(g.get("glGetProgramInfoLog"))
|
||||
c.gpGetProgramiv = C.uintptr_t(g.get("glGetProgramiv"))
|
||||
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"))
|
||||
c.gpRenderbufferStorage = C.uintptr_t(g.get("glRenderbufferStorage"))
|
||||
c.gpScissor = C.uintptr_t(g.get("glScissor"))
|
||||
c.gpShaderSource = C.uintptr_t(g.get("glShaderSource"))
|
||||
c.gpStencilFunc = C.uintptr_t(g.get("glStencilFunc"))
|
||||
c.gpStencilOpSeparate = C.uintptr_t(g.get("glStencilOpSeparate"))
|
||||
c.gpTexImage2D = C.uintptr_t(g.get("glTexImage2D"))
|
||||
c.gpTexParameteri = C.uintptr_t(g.get("glTexParameteri"))
|
||||
c.gpTexSubImage2D = C.uintptr_t(g.get("glTexSubImage2D"))
|
||||
c.gpUniform1fv = C.uintptr_t(g.get("glUniform1fv"))
|
||||
c.gpUniform1i = C.uintptr_t(g.get("glUniform1i"))
|
||||
c.gpUniform1iv = C.uintptr_t(g.get("glUniform1iv"))
|
||||
c.gpUniform2fv = C.uintptr_t(g.get("glUniform2fv"))
|
||||
c.gpUniform2iv = C.uintptr_t(g.get("glUniform2iv"))
|
||||
c.gpUniform3fv = C.uintptr_t(g.get("glUniform3fv"))
|
||||
c.gpUniform3iv = C.uintptr_t(g.get("glUniform3iv"))
|
||||
c.gpUniform4fv = C.uintptr_t(g.get("glUniform4fv"))
|
||||
c.gpUniform4iv = C.uintptr_t(g.get("glUniform4iv"))
|
||||
c.gpUniformMatrix2fv = C.uintptr_t(g.get("glUniformMatrix2fv"))
|
||||
c.gpUniformMatrix3fv = C.uintptr_t(g.get("glUniformMatrix3fv"))
|
||||
c.gpUniformMatrix4fv = C.uintptr_t(g.get("glUniformMatrix4fv"))
|
||||
c.gpUseProgram = C.uintptr_t(g.get("glUseProgram"))
|
||||
c.gpVertexAttribPointer = C.uintptr_t(g.get("glVertexAttribPointer"))
|
||||
c.gpViewport = C.uintptr_t(g.get("glViewport"))
|
||||
|
||||
return g.error()
|
||||
}
|
||||
Generated
Vendored
+634
@@ -0,0 +1,634 @@
|
||||
// Copyright 2022 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 gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/jsutil"
|
||||
)
|
||||
|
||||
type defaultContext struct {
|
||||
fnActiveTexture js.Value
|
||||
fnAttachShader js.Value
|
||||
fnBindAttribLocation js.Value
|
||||
fnBindBuffer js.Value
|
||||
fnBindFramebuffer js.Value
|
||||
fnBindRenderbuffer js.Value
|
||||
fnBindTexture js.Value
|
||||
fnBindVertexArray js.Value
|
||||
fnBlendEquationSeparate js.Value
|
||||
fnBlendFuncSeparate js.Value
|
||||
fnBufferData js.Value
|
||||
fnBufferSubData js.Value
|
||||
fnCheckFramebufferStatus js.Value
|
||||
fnClear js.Value
|
||||
fnColorMask js.Value
|
||||
fnCompileShader js.Value
|
||||
fnCreateBuffer js.Value
|
||||
fnCreateFramebuffer js.Value
|
||||
fnCreateProgram js.Value
|
||||
fnCreateRenderbuffer js.Value
|
||||
fnCreateShader js.Value
|
||||
fnCreateTexture js.Value
|
||||
fnCreateVertexArray js.Value
|
||||
fnDeleteBuffer js.Value
|
||||
fnDeleteFramebuffer js.Value
|
||||
fnDeleteProgram js.Value
|
||||
fnDeleteRenderbuffer js.Value
|
||||
fnDeleteShader js.Value
|
||||
fnDeleteTexture js.Value
|
||||
fnDeleteVertexArray js.Value
|
||||
fnDisable js.Value
|
||||
fnDisableVertexAttribArray js.Value
|
||||
fnDrawElements js.Value
|
||||
fnEnable js.Value
|
||||
fnEnableVertexAttribArray js.Value
|
||||
fnFramebufferRenderbuffer js.Value
|
||||
fnFramebufferTexture2D js.Value
|
||||
fnFlush js.Value
|
||||
fnGetError 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
|
||||
fnRenderbufferStorage js.Value
|
||||
fnScissor js.Value
|
||||
fnShaderSource js.Value
|
||||
fnStencilFunc js.Value
|
||||
fnStencilMask js.Value
|
||||
fnStencilOpSeparate js.Value
|
||||
fnTexImage2D js.Value
|
||||
fnTexSubImage2D js.Value
|
||||
fnTexParameteri js.Value
|
||||
fnUniform1fv js.Value
|
||||
fnUniform1i js.Value
|
||||
fnUniform1iv js.Value
|
||||
fnUniform2fv js.Value
|
||||
fnUniform2iv js.Value
|
||||
fnUniform3fv js.Value
|
||||
fnUniform3iv js.Value
|
||||
fnUniform4fv js.Value
|
||||
fnUniform4iv js.Value
|
||||
fnUniformMatrix2fv js.Value
|
||||
fnUniformMatrix3fv js.Value
|
||||
fnUniformMatrix4fv js.Value
|
||||
fnUseProgram js.Value
|
||||
fnVertexAttribPointer js.Value
|
||||
fnViewport js.Value
|
||||
|
||||
buffers values
|
||||
framebuffers values
|
||||
programs values
|
||||
renderbuffers values
|
||||
shaders values
|
||||
textures values
|
||||
vertexArrays values
|
||||
uniformLocations map[uint32]*values
|
||||
}
|
||||
|
||||
type values struct {
|
||||
idToValue map[uint32]js.Value
|
||||
lastID uint32
|
||||
}
|
||||
|
||||
func (v *values) create(value js.Value) uint32 {
|
||||
v.lastID++
|
||||
id := v.lastID
|
||||
if v.idToValue == nil {
|
||||
v.idToValue = map[uint32]js.Value{}
|
||||
}
|
||||
v.idToValue[id] = value
|
||||
return id
|
||||
}
|
||||
|
||||
func (v *values) get(id uint32) js.Value {
|
||||
return v.idToValue[id]
|
||||
}
|
||||
|
||||
func (v *values) getID(value js.Value) (uint32, bool) {
|
||||
for id, v := range v.idToValue {
|
||||
if v.Equal(value) {
|
||||
return id, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (v *values) getOrCreate(value js.Value) uint32 {
|
||||
id, ok := v.getID(value)
|
||||
if ok {
|
||||
return id
|
||||
}
|
||||
return v.create(value)
|
||||
}
|
||||
|
||||
func (v *values) delete(id uint32) {
|
||||
delete(v.idToValue, id)
|
||||
}
|
||||
|
||||
func NewDefaultContext(v js.Value) (Context, error) {
|
||||
// Passing a Go string to the JS world is expensive. This causes conversion to UTF-16 (#1438).
|
||||
// In order to reduce the cost when calling functions, create the function objects by bind and use them.
|
||||
g := &defaultContext{
|
||||
fnActiveTexture: v.Get("activeTexture").Call("bind", v),
|
||||
fnAttachShader: v.Get("attachShader").Call("bind", v),
|
||||
fnBindAttribLocation: v.Get("bindAttribLocation").Call("bind", v),
|
||||
fnBindBuffer: v.Get("bindBuffer").Call("bind", v),
|
||||
fnBindFramebuffer: v.Get("bindFramebuffer").Call("bind", v),
|
||||
fnBindRenderbuffer: v.Get("bindRenderbuffer").Call("bind", v),
|
||||
fnBindTexture: v.Get("bindTexture").Call("bind", v),
|
||||
fnBindVertexArray: v.Get("bindVertexArray").Call("bind", v),
|
||||
fnBlendEquationSeparate: v.Get("blendEquationSeparate").Call("bind", v),
|
||||
fnBlendFuncSeparate: v.Get("blendFuncSeparate").Call("bind", v),
|
||||
fnBufferData: v.Get("bufferData").Call("bind", v),
|
||||
fnBufferSubData: v.Get("bufferSubData").Call("bind", v),
|
||||
fnCheckFramebufferStatus: v.Get("checkFramebufferStatus").Call("bind", v),
|
||||
fnClear: v.Get("clear").Call("bind", v),
|
||||
fnColorMask: v.Get("colorMask").Call("bind", v),
|
||||
fnCompileShader: v.Get("compileShader").Call("bind", v),
|
||||
fnCreateBuffer: v.Get("createBuffer").Call("bind", v),
|
||||
fnCreateFramebuffer: v.Get("createFramebuffer").Call("bind", v),
|
||||
fnCreateProgram: v.Get("createProgram").Call("bind", v),
|
||||
fnCreateRenderbuffer: v.Get("createRenderbuffer").Call("bind", v),
|
||||
fnCreateShader: v.Get("createShader").Call("bind", v),
|
||||
fnCreateTexture: v.Get("createTexture").Call("bind", v),
|
||||
fnCreateVertexArray: v.Get("createVertexArray").Call("bind", v),
|
||||
fnDeleteBuffer: v.Get("deleteBuffer").Call("bind", v),
|
||||
fnDeleteFramebuffer: v.Get("deleteFramebuffer").Call("bind", v),
|
||||
fnDeleteProgram: v.Get("deleteProgram").Call("bind", v),
|
||||
fnDeleteRenderbuffer: v.Get("deleteRenderbuffer").Call("bind", v),
|
||||
fnDeleteShader: v.Get("deleteShader").Call("bind", v),
|
||||
fnDeleteTexture: v.Get("deleteTexture").Call("bind", v),
|
||||
fnDeleteVertexArray: v.Get("deleteVertexArray").Call("bind", v),
|
||||
fnDisable: v.Get("disable").Call("bind", v),
|
||||
fnDisableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
|
||||
fnDrawElements: v.Get("drawElements").Call("bind", v),
|
||||
fnEnable: v.Get("enable").Call("bind", v),
|
||||
fnEnableVertexAttribArray: v.Get("enableVertexAttribArray").Call("bind", v),
|
||||
fnFramebufferRenderbuffer: v.Get("framebufferRenderbuffer").Call("bind", v),
|
||||
fnFramebufferTexture2D: v.Get("framebufferTexture2D").Call("bind", v),
|
||||
fnFlush: v.Get("flush").Call("bind", v),
|
||||
fnGetError: v.Get("getError").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),
|
||||
fnRenderbufferStorage: v.Get("renderbufferStorage").Call("bind", v),
|
||||
fnScissor: v.Get("scissor").Call("bind", v),
|
||||
fnShaderSource: v.Get("shaderSource").Call("bind", v),
|
||||
fnStencilFunc: v.Get("stencilFunc").Call("bind", v),
|
||||
fnStencilMask: v.Get("stencilMask").Call("bind", v),
|
||||
fnStencilOpSeparate: v.Get("stencilOpSeparate").Call("bind", v),
|
||||
fnTexImage2D: v.Get("texImage2D").Call("bind", v),
|
||||
fnTexSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
||||
fnTexParameteri: v.Get("texParameteri").Call("bind", v),
|
||||
fnUniform1fv: v.Get("uniform1fv").Call("bind", v),
|
||||
fnUniform1i: v.Get("uniform1i").Call("bind", v),
|
||||
fnUniform1iv: v.Get("uniform1iv").Call("bind", v),
|
||||
fnUniform2fv: v.Get("uniform2fv").Call("bind", v),
|
||||
fnUniform2iv: v.Get("uniform2iv").Call("bind", v),
|
||||
fnUniform3fv: v.Get("uniform3fv").Call("bind", v),
|
||||
fnUniform3iv: v.Get("uniform3iv").Call("bind", v),
|
||||
fnUniform4fv: v.Get("uniform4fv").Call("bind", v),
|
||||
fnUniform4iv: v.Get("uniform4iv").Call("bind", v),
|
||||
fnUniformMatrix2fv: v.Get("uniformMatrix2fv").Call("bind", v),
|
||||
fnUniformMatrix3fv: v.Get("uniformMatrix3fv").Call("bind", v),
|
||||
fnUniformMatrix4fv: v.Get("uniformMatrix4fv").Call("bind", v),
|
||||
fnUseProgram: v.Get("useProgram").Call("bind", v),
|
||||
fnVertexAttribPointer: v.Get("vertexAttribPointer").Call("bind", v),
|
||||
fnViewport: v.Get("viewport").Call("bind", v),
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) getUniformLocation(location int32) js.Value {
|
||||
program := uint32(location) >> 5
|
||||
return c.uniformLocations[program].get(uint32(location) & ((1 << 5) - 1))
|
||||
}
|
||||
|
||||
func (c *defaultContext) LoadFunctions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsES() bool {
|
||||
// WebGL is compatible with GLES.
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *defaultContext) ActiveTexture(texture uint32) {
|
||||
c.fnActiveTexture.Invoke(texture)
|
||||
}
|
||||
|
||||
func (c *defaultContext) AttachShader(program uint32, shader uint32) {
|
||||
c.fnAttachShader.Invoke(c.programs.get(program), c.shaders.get(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
c.fnBindAttribLocation.Invoke(c.programs.get(program), index, name)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindBuffer(target uint32, buffer uint32) {
|
||||
c.fnBindBuffer.Invoke(target, c.buffers.get(buffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindFramebuffer(target uint32, framebuffer uint32) {
|
||||
c.fnBindFramebuffer.Invoke(target, c.framebuffers.get(framebuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindRenderbuffer(target uint32, renderbuffer uint32) {
|
||||
c.fnBindRenderbuffer.Invoke(target, c.renderbuffers.get(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindTexture(target uint32, texture uint32) {
|
||||
c.fnBindTexture.Invoke(target, c.textures.get(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindVertexArray(array uint32) {
|
||||
c.fnBindVertexArray.Invoke(c.vertexArrays.get(array))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
c.fnBlendEquationSeparate.Invoke(modeRGB, modeAlpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
c.fnBlendFuncSeparate.Invoke(srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferInit(target uint32, size int, usage uint32) {
|
||||
c.fnBufferData.Invoke(target, size, usage)
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferSubData(target uint32, offset int, data []byte) {
|
||||
l := len(data)
|
||||
arr := jsutil.TemporaryUint8ArrayFromUint8Slice(l, data)
|
||||
c.fnBufferSubData.Invoke(target, offset, arr, 0, l)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CheckFramebufferStatus(target uint32) uint32 {
|
||||
return uint32(c.fnCheckFramebufferStatus.Invoke(target).Int())
|
||||
}
|
||||
|
||||
func (c *defaultContext) Clear(mask uint32) {
|
||||
c.fnClear.Invoke(mask)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ColorMask(red, green, blue, alpha bool) {
|
||||
c.fnColorMask.Invoke(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CompileShader(shader uint32) {
|
||||
c.fnCompileShader.Invoke(c.shaders.get(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateBuffer() uint32 {
|
||||
return c.buffers.create(c.fnCreateBuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateFramebuffer() uint32 {
|
||||
return c.framebuffers.create(c.fnCreateFramebuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateProgram() uint32 {
|
||||
return c.programs.create(c.fnCreateProgram.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateRenderbuffer() uint32 {
|
||||
return c.renderbuffers.create(c.fnCreateRenderbuffer.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateShader(xtype uint32) uint32 {
|
||||
return c.shaders.create(c.fnCreateShader.Invoke(xtype))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateTexture() uint32 {
|
||||
return c.textures.create(c.fnCreateTexture.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateVertexArray() uint32 {
|
||||
return c.vertexArrays.create(c.fnCreateVertexArray.Invoke())
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteBuffer(buffer uint32) {
|
||||
c.fnDeleteBuffer.Invoke(c.buffers.get(buffer))
|
||||
c.buffers.delete(buffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteFramebuffer(framebuffer uint32) {
|
||||
c.fnDeleteFramebuffer.Invoke(c.framebuffers.get(framebuffer))
|
||||
c.framebuffers.delete(framebuffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteProgram(program uint32) {
|
||||
c.fnDeleteProgram.Invoke(c.programs.get(program))
|
||||
c.programs.delete(program)
|
||||
delete(c.uniformLocations, program)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteRenderbuffer(renderbuffer uint32) {
|
||||
c.fnDeleteRenderbuffer.Invoke(c.renderbuffers.get(renderbuffer))
|
||||
c.renderbuffers.delete(renderbuffer)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteShader(shader uint32) {
|
||||
c.fnDeleteShader.Invoke(c.shaders.get(shader))
|
||||
c.shaders.delete(shader)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteTexture(texture uint32) {
|
||||
c.fnDeleteTexture.Invoke(c.textures.get(texture))
|
||||
c.textures.delete(texture)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteVertexArray(array uint32) {
|
||||
c.fnDeleteVertexArray.Invoke(c.vertexArrays.get(array))
|
||||
c.textures.delete(array)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Disable(cap uint32) {
|
||||
c.fnDisable.Invoke(cap)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DisableVertexAttribArray(index uint32) {
|
||||
c.fnDisableVertexAttribArray.Invoke(index)
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
|
||||
c.fnDrawElements.Invoke(mode, count, xtype, offset)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Enable(cap uint32) {
|
||||
c.fnEnable.Invoke(cap)
|
||||
}
|
||||
|
||||
func (c *defaultContext) EnableVertexAttribArray(index uint32) {
|
||||
c.fnEnableVertexAttribArray.Invoke(index)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Flush() {
|
||||
c.fnFlush.Invoke()
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
c.fnFramebufferRenderbuffer.Invoke(target, attachment, renderbuffertarget, c.renderbuffers.get(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
|
||||
c.fnFramebufferTexture2D.Invoke(target, attachment, textarget, c.textures.get(texture), level)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetError() uint32 {
|
||||
return uint32(c.fnGetError.Invoke().Int())
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
ret := c.fnGetParameter.Invoke(pname)
|
||||
switch pname {
|
||||
case FRAMEBUFFER_BINDING:
|
||||
id, ok := c.framebuffers.getID(ret)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return int(id)
|
||||
case MAX_TEXTURE_SIZE:
|
||||
return ret.Int()
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected pname at GetInteger: %d", pname))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
return c.fnGetProgramInfoLog.Invoke(c.programs.get(program)).String()
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
v := c.fnGetProgramParameter.Invoke(c.programs.get(program), pname)
|
||||
switch v.Type() {
|
||||
case js.TypeNumber:
|
||||
return v.Int()
|
||||
case js.TypeBoolean:
|
||||
if v.Bool() {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected return type at GetProgrami: %v", v))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
return c.fnGetShaderInfoLog.Invoke(c.shaders.get(shader)).String()
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderi(shader uint32, pname uint32) int {
|
||||
v := c.fnGetShaderParameter.Invoke(c.shaders.get(shader), pname)
|
||||
switch v.Type() {
|
||||
case js.TypeNumber:
|
||||
return v.Int()
|
||||
case js.TypeBoolean:
|
||||
if v.Bool() {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
default:
|
||||
panic(fmt.Sprintf("gl: unexpected return type at GetShaderi: %v", v))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
location := c.fnGetUniformLocation.Invoke(c.programs.get(program), name)
|
||||
if c.uniformLocations == nil {
|
||||
c.uniformLocations = map[uint32]*values{}
|
||||
}
|
||||
vs, ok := c.uniformLocations[program]
|
||||
if !ok {
|
||||
vs = &values{}
|
||||
c.uniformLocations[program] = vs
|
||||
}
|
||||
idx := vs.getOrCreate(location)
|
||||
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))
|
||||
}
|
||||
|
||||
func (c *defaultContext) PixelStorei(pname uint32, param int32) {
|
||||
c.fnPixelStorei.Invoke(pname, param)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
|
||||
if dst == nil {
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, 0)
|
||||
return
|
||||
}
|
||||
p := jsutil.TemporaryUint8ArrayFromUint8Slice(len(dst), nil)
|
||||
c.fnReadPixels.Invoke(x, y, width, height, format, xtype, p)
|
||||
js.CopyBytesToGo(dst, p)
|
||||
}
|
||||
|
||||
func (c *defaultContext) RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32) {
|
||||
c.fnRenderbufferStorage.Invoke(target, internalFormat, width, height)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Scissor(x, y, width, height int32) {
|
||||
c.fnScissor.Invoke(x, y, width, height)
|
||||
}
|
||||
|
||||
func (c *defaultContext) ShaderSource(shader uint32, xstring string) {
|
||||
c.fnShaderSource.Invoke(c.shaders.get(shader), xstring)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilFunc(func_ uint32, ref int32, mask uint32) {
|
||||
c.fnStencilFunc.Invoke(func_, ref, mask)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilOpSeparate(face, sfail, dpfail, dppass uint32) {
|
||||
c.fnStencilOpSeparate.Invoke(face, sfail, dpfail, dppass)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
if pixels != nil {
|
||||
panic("gl: TexImage2D with non-nil pixels is not implemented")
|
||||
}
|
||||
c.fnTexImage2D.Invoke(target, level, internalformat, width, height, 0, format, xtype, nil)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
c.fnTexParameteri.Invoke(target, pname, param)
|
||||
}
|
||||
|
||||
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)
|
||||
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
// GLsizei width, GLsizei height,
|
||||
// GLenum format, GLenum type, ArrayBufferView pixels, srcOffset);
|
||||
c.fnTexSubImage2D.Invoke(target, level, xoffset, yoffset, width, height, format, xtype, arr, 0)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1fv(location int32, value []float32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryFloat32Array(len(value), value)
|
||||
c.fnUniform1fv.Invoke(l, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1i(location int32, v0 int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
c.fnUniform1i.Invoke(l, v0)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1iv(location int32, value []int32) {
|
||||
l := c.getUniformLocation(location)
|
||||
arr := jsutil.TemporaryInt32Array(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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
c.fnUniformMatrix4fv.Invoke(l, false, arr, 0, len(value))
|
||||
}
|
||||
|
||||
func (c *defaultContext) UseProgram(program uint32) {
|
||||
c.fnUseProgram.Invoke(c.programs.get(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
|
||||
c.fnVertexAttribPointer.Invoke(index, size, xtype, normalized, stride, offset)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Viewport(x int32, y int32, width int32, height int32) {
|
||||
c.fnViewport.Invoke(x, y, width, height)
|
||||
}
|
||||
Generated
Vendored
+569
@@ -0,0 +1,569 @@
|
||||
// Copyright 2022 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 || windows
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
type defaultContext struct {
|
||||
gpActiveTexture uintptr
|
||||
gpAttachShader uintptr
|
||||
gpBindAttribLocation uintptr
|
||||
gpBindBuffer uintptr
|
||||
gpBindFramebuffer uintptr
|
||||
gpBindRenderbuffer uintptr
|
||||
gpBindTexture uintptr
|
||||
gpBindVertexArray uintptr
|
||||
gpBlendEquationSeparate uintptr
|
||||
gpBlendFuncSeparate uintptr
|
||||
gpBufferData uintptr
|
||||
gpBufferSubData uintptr
|
||||
gpCheckFramebufferStatus uintptr
|
||||
gpClear uintptr
|
||||
gpColorMask uintptr
|
||||
gpCompileShader uintptr
|
||||
gpCreateProgram uintptr
|
||||
gpCreateShader uintptr
|
||||
gpDeleteBuffers uintptr
|
||||
gpDeleteFramebuffers uintptr
|
||||
gpDeleteProgram uintptr
|
||||
gpDeleteRenderbuffers uintptr
|
||||
gpDeleteShader uintptr
|
||||
gpDeleteTextures uintptr
|
||||
gpDeleteVertexArrays uintptr
|
||||
gpDisable uintptr
|
||||
gpDisableVertexAttribArray uintptr
|
||||
gpDrawElements uintptr
|
||||
gpEnable uintptr
|
||||
gpEnableVertexAttribArray uintptr
|
||||
gpFlush uintptr
|
||||
gpFramebufferRenderbuffer uintptr
|
||||
gpFramebufferTexture2D uintptr
|
||||
gpGenBuffers uintptr
|
||||
gpGenFramebuffers uintptr
|
||||
gpGenRenderbuffers uintptr
|
||||
gpGenTextures uintptr
|
||||
gpGenVertexArrays uintptr
|
||||
gpGetError uintptr
|
||||
gpGetIntegerv uintptr
|
||||
gpGetProgramInfoLog uintptr
|
||||
gpGetProgramiv uintptr
|
||||
gpGetShaderInfoLog uintptr
|
||||
gpGetShaderiv uintptr
|
||||
gpGetUniformLocation uintptr
|
||||
gpIsFramebuffer uintptr
|
||||
gpIsProgram uintptr
|
||||
gpIsRenderbuffer uintptr
|
||||
gpLinkProgram uintptr
|
||||
gpPixelStorei uintptr
|
||||
gpReadPixels uintptr
|
||||
gpRenderbufferStorage uintptr
|
||||
gpScissor uintptr
|
||||
gpShaderSource uintptr
|
||||
gpStencilFunc uintptr
|
||||
gpStencilOpSeparate uintptr
|
||||
gpTexImage2D uintptr
|
||||
gpTexParameteri uintptr
|
||||
gpTexSubImage2D uintptr
|
||||
gpUniform1fv uintptr
|
||||
gpUniform1i uintptr
|
||||
gpUniform1iv uintptr
|
||||
gpUniform2fv uintptr
|
||||
gpUniform2iv uintptr
|
||||
gpUniform3fv uintptr
|
||||
gpUniform3iv uintptr
|
||||
gpUniform4fv uintptr
|
||||
gpUniform4iv uintptr
|
||||
gpUniformMatrix2fv uintptr
|
||||
gpUniformMatrix3fv uintptr
|
||||
gpUniformMatrix4fv uintptr
|
||||
gpUseProgram uintptr
|
||||
gpVertexAttribPointer uintptr
|
||||
gpViewport uintptr
|
||||
|
||||
isES bool
|
||||
}
|
||||
|
||||
func NewDefaultContext() (Context, error) {
|
||||
ctx := &defaultContext{}
|
||||
if err := ctx.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *defaultContext) IsES() bool {
|
||||
return c.isES
|
||||
}
|
||||
|
||||
func (c *defaultContext) ActiveTexture(texture uint32) {
|
||||
purego.SyscallN(c.gpActiveTexture, uintptr(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) AttachShader(program uint32, shader uint32) {
|
||||
purego.SyscallN(c.gpAttachShader, uintptr(program), uintptr(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
cname, free := cStr(name)
|
||||
defer free()
|
||||
purego.SyscallN(c.gpBindAttribLocation, uintptr(program), uintptr(index), uintptr(unsafe.Pointer(cname)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindBuffer(target uint32, buffer uint32) {
|
||||
purego.SyscallN(c.gpBindBuffer, uintptr(target), uintptr(buffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindFramebuffer(target uint32, framebuffer uint32) {
|
||||
purego.SyscallN(c.gpBindFramebuffer, uintptr(target), uintptr(framebuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindRenderbuffer(target uint32, renderbuffer uint32) {
|
||||
purego.SyscallN(c.gpBindRenderbuffer, uintptr(target), uintptr(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindTexture(target uint32, texture uint32) {
|
||||
purego.SyscallN(c.gpBindTexture, uintptr(target), uintptr(texture))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BindVertexArray(array uint32) {
|
||||
purego.SyscallN(c.gpBindVertexArray, uintptr(array))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
purego.SyscallN(c.gpBlendEquationSeparate, uintptr(modeRGB), uintptr(modeAlpha))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
purego.SyscallN(c.gpBlendFuncSeparate, uintptr(srcRGB), uintptr(dstRGB), uintptr(srcAlpha), uintptr(dstAlpha))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferInit(target uint32, size int, usage uint32) {
|
||||
purego.SyscallN(c.gpBufferData, uintptr(target), uintptr(size), 0, uintptr(usage))
|
||||
}
|
||||
|
||||
func (c *defaultContext) BufferSubData(target uint32, offset int, data []byte) {
|
||||
purego.SyscallN(c.gpBufferSubData, uintptr(target), uintptr(offset), uintptr(len(data)), uintptr(unsafe.Pointer(&data[0])))
|
||||
runtime.KeepAlive(data)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CheckFramebufferStatus(target uint32) uint32 {
|
||||
ret, _, _ := purego.SyscallN(c.gpCheckFramebufferStatus, uintptr(target))
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Clear(mask uint32) {
|
||||
purego.SyscallN(c.gpClear, uintptr(mask))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ColorMask(red bool, green bool, blue bool, alpha bool) {
|
||||
purego.SyscallN(c.gpColorMask, uintptr(boolToInt(red)), uintptr(boolToInt(green)), uintptr(boolToInt(blue)), uintptr(boolToInt(alpha)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CompileShader(shader uint32) {
|
||||
purego.SyscallN(c.gpCompileShader, uintptr(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateBuffer() uint32 {
|
||||
var buffer uint32
|
||||
purego.SyscallN(c.gpGenBuffers, 1, uintptr(unsafe.Pointer(&buffer)))
|
||||
return buffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateFramebuffer() uint32 {
|
||||
var framebuffer uint32
|
||||
purego.SyscallN(c.gpGenFramebuffers, 1, uintptr(unsafe.Pointer(&framebuffer)))
|
||||
return framebuffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateProgram() uint32 {
|
||||
ret, _, _ := purego.SyscallN(c.gpCreateProgram)
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateRenderbuffer() uint32 {
|
||||
var renderbuffer uint32
|
||||
purego.SyscallN(c.gpGenRenderbuffers, 1, uintptr(unsafe.Pointer(&renderbuffer)))
|
||||
return renderbuffer
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateShader(xtype uint32) uint32 {
|
||||
ret, _, _ := purego.SyscallN(c.gpCreateShader, uintptr(xtype))
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateTexture() uint32 {
|
||||
var texture uint32
|
||||
purego.SyscallN(c.gpGenTextures, 1, uintptr(unsafe.Pointer(&texture)))
|
||||
return texture
|
||||
}
|
||||
|
||||
func (c *defaultContext) CreateVertexArray() uint32 {
|
||||
var array uint32
|
||||
purego.SyscallN(c.gpGenVertexArrays, 1, uintptr(unsafe.Pointer(&array)))
|
||||
return array
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteBuffer(buffer uint32) {
|
||||
purego.SyscallN(c.gpDeleteBuffers, 1, uintptr(unsafe.Pointer(&buffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteFramebuffer(framebuffer uint32) {
|
||||
purego.SyscallN(c.gpDeleteFramebuffers, 1, uintptr(unsafe.Pointer(&framebuffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteProgram(program uint32) {
|
||||
purego.SyscallN(c.gpDeleteProgram, uintptr(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteRenderbuffer(renderbuffer uint32) {
|
||||
purego.SyscallN(c.gpDeleteRenderbuffers, 1, uintptr(unsafe.Pointer(&renderbuffer)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteShader(shader uint32) {
|
||||
purego.SyscallN(c.gpDeleteShader, uintptr(shader))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteTexture(texture uint32) {
|
||||
purego.SyscallN(c.gpDeleteTextures, 1, uintptr(unsafe.Pointer(&texture)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DeleteVertexArray(array uint32) {
|
||||
purego.SyscallN(c.gpDeleteVertexArrays, 1, uintptr(unsafe.Pointer(&array)))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Disable(cap uint32) {
|
||||
purego.SyscallN(c.gpDisable, uintptr(cap))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DisableVertexAttribArray(index uint32) {
|
||||
purego.SyscallN(c.gpDisableVertexAttribArray, uintptr(index))
|
||||
}
|
||||
|
||||
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
|
||||
purego.SyscallN(c.gpDrawElements, uintptr(mode), uintptr(count), uintptr(xtype), uintptr(offset))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Enable(cap uint32) {
|
||||
purego.SyscallN(c.gpEnable, uintptr(cap))
|
||||
}
|
||||
|
||||
func (c *defaultContext) EnableVertexAttribArray(index uint32) {
|
||||
purego.SyscallN(c.gpEnableVertexAttribArray, uintptr(index))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Flush() {
|
||||
purego.SyscallN(c.gpFlush)
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
purego.SyscallN(c.gpFramebufferRenderbuffer, uintptr(target), uintptr(attachment), uintptr(renderbuffertarget), uintptr(renderbuffer))
|
||||
}
|
||||
|
||||
func (c *defaultContext) FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32) {
|
||||
purego.SyscallN(c.gpFramebufferTexture2D, uintptr(target), uintptr(attachment), uintptr(textarget), uintptr(texture), uintptr(level))
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetError() uint32 {
|
||||
ret, _, _ := purego.SyscallN(c.gpGetError)
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetInteger(pname uint32) int {
|
||||
var dst int32
|
||||
purego.SyscallN(c.gpGetIntegerv, uintptr(pname), uintptr(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgramInfoLog(program uint32) string {
|
||||
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
|
||||
infoLog := make([]byte, bufSize)
|
||||
purego.SyscallN(c.gpGetProgramInfoLog, uintptr(program), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
|
||||
var dst int32
|
||||
purego.SyscallN(c.gpGetProgramiv, uintptr(program), uintptr(pname), uintptr(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
|
||||
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
|
||||
infoLog := make([]byte, bufSize)
|
||||
purego.SyscallN(c.gpGetShaderInfoLog, uintptr(shader), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
|
||||
return string(infoLog)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetShaderi(shader uint32, pname uint32) int {
|
||||
var dst int32
|
||||
purego.SyscallN(c.gpGetShaderiv, uintptr(shader), uintptr(pname), uintptr(unsafe.Pointer(&dst)))
|
||||
return int(dst)
|
||||
}
|
||||
|
||||
func (c *defaultContext) GetUniformLocation(program uint32, name string) int32 {
|
||||
cname, free := cStr(name)
|
||||
defer free()
|
||||
ret, _, _ := purego.SyscallN(c.gpGetUniformLocation, uintptr(program), uintptr(unsafe.Pointer(cname)))
|
||||
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))
|
||||
}
|
||||
|
||||
func (c *defaultContext) PixelStorei(pname uint32, param int32) {
|
||||
purego.SyscallN(c.gpPixelStorei, uintptr(pname), uintptr(param))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ReadPixels(dst []byte, x int32, y int32, width int32, height int32, format uint32, xtype uint32) {
|
||||
purego.SyscallN(c.gpReadPixels, uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(format), uintptr(xtype), uintptr(unsafe.Pointer(&dst[0])))
|
||||
}
|
||||
|
||||
func (c *defaultContext) RenderbufferStorage(target uint32, internalformat uint32, width int32, height int32) {
|
||||
purego.SyscallN(c.gpRenderbufferStorage, uintptr(target), uintptr(internalformat), uintptr(width), uintptr(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Scissor(x int32, y int32, width int32, height int32) {
|
||||
purego.SyscallN(c.gpScissor, uintptr(x), uintptr(y), uintptr(width), uintptr(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) ShaderSource(shader uint32, xstring string) {
|
||||
cstring, free := cStr(xstring)
|
||||
defer free()
|
||||
purego.SyscallN(c.gpShaderSource, uintptr(shader), 1, uintptr(unsafe.Pointer(&cstring)), 0)
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilFunc(xfunc uint32, ref int32, mask uint32) {
|
||||
purego.SyscallN(c.gpStencilFunc, uintptr(xfunc), uintptr(ref), uintptr(mask))
|
||||
}
|
||||
|
||||
func (c *defaultContext) StencilOpSeparate(face uint32, fail uint32, zfail uint32, zpass uint32) {
|
||||
purego.SyscallN(c.gpStencilOpSeparate, uintptr(face), uintptr(fail), uintptr(zfail), uintptr(zpass))
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
var ptr *byte
|
||||
if len(pixels) > 0 {
|
||||
ptr = &pixels[0]
|
||||
}
|
||||
purego.SyscallN(c.gpTexImage2D, uintptr(target), uintptr(level), uintptr(internalformat), uintptr(width), uintptr(height), 0, uintptr(format), uintptr(xtype), uintptr(unsafe.Pointer(ptr)))
|
||||
runtime.KeepAlive(pixels)
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
purego.SyscallN(c.gpTexParameteri, uintptr(target), uintptr(pname), uintptr(param))
|
||||
}
|
||||
|
||||
func (c *defaultContext) TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||
purego.SyscallN(c.gpTexSubImage2D, uintptr(target), uintptr(level), uintptr(xoffset), uintptr(yoffset), uintptr(width), uintptr(height), uintptr(format), uintptr(xtype), uintptr(unsafe.Pointer(&pixels[0])))
|
||||
runtime.KeepAlive(pixels)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniform1fv, uintptr(location), uintptr(len(value)), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1i(location int32, v0 int32) {
|
||||
purego.SyscallN(c.gpUniform1i, uintptr(location), uintptr(v0))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform1iv(location int32, value []int32) {
|
||||
purego.SyscallN(c.gpUniform1iv, uintptr(location), uintptr(len(value)), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniform2fv, uintptr(location), uintptr(len(value)/2), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform2iv(location int32, value []int32) {
|
||||
purego.SyscallN(c.gpUniform2iv, uintptr(location), uintptr(len(value)/2), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniform3fv, uintptr(location), uintptr(len(value)/3), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform3iv(location int32, value []int32) {
|
||||
purego.SyscallN(c.gpUniform3iv, uintptr(location), uintptr(len(value)/3), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniform4fv, uintptr(location), uintptr(len(value)/4), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) Uniform4iv(location int32, value []int32) {
|
||||
purego.SyscallN(c.gpUniform4iv, uintptr(location), uintptr(len(value)/4), uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix2fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniformMatrix2fv, uintptr(location), uintptr(len(value)/4), 0, uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix3fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniformMatrix3fv, uintptr(location), uintptr(len(value)/9), 0, uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UniformMatrix4fv(location int32, value []float32) {
|
||||
purego.SyscallN(c.gpUniformMatrix4fv, uintptr(location), uintptr(len(value)/16), 0, uintptr(unsafe.Pointer(&value[0])))
|
||||
runtime.KeepAlive(value)
|
||||
}
|
||||
|
||||
func (c *defaultContext) UseProgram(program uint32) {
|
||||
purego.SyscallN(c.gpUseProgram, uintptr(program))
|
||||
}
|
||||
|
||||
func (c *defaultContext) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int) {
|
||||
purego.SyscallN(c.gpVertexAttribPointer, uintptr(index), uintptr(size), uintptr(xtype), uintptr(boolToInt(normalized)), uintptr(stride), uintptr(offset))
|
||||
}
|
||||
|
||||
func (c *defaultContext) Viewport(x int32, y int32, width int32, height int32) {
|
||||
purego.SyscallN(c.gpViewport, uintptr(x), uintptr(y), uintptr(width), uintptr(height))
|
||||
}
|
||||
|
||||
func (c *defaultContext) LoadFunctions() error {
|
||||
g := procAddressGetter{ctx: c}
|
||||
|
||||
c.gpActiveTexture = g.get("glActiveTexture")
|
||||
c.gpAttachShader = g.get("glAttachShader")
|
||||
c.gpBindAttribLocation = g.get("glBindAttribLocation")
|
||||
c.gpBindBuffer = g.get("glBindBuffer")
|
||||
c.gpBindFramebuffer = g.get("glBindFramebuffer")
|
||||
c.gpBindRenderbuffer = g.get("glBindRenderbuffer")
|
||||
c.gpBindTexture = g.get("glBindTexture")
|
||||
c.gpBindVertexArray = g.get("glBindVertexArray")
|
||||
c.gpBlendEquationSeparate = g.get("glBlendEquationSeparate")
|
||||
c.gpBlendFuncSeparate = g.get("glBlendFuncSeparate")
|
||||
c.gpBufferData = g.get("glBufferData")
|
||||
c.gpBufferSubData = g.get("glBufferSubData")
|
||||
c.gpCheckFramebufferStatus = g.get("glCheckFramebufferStatus")
|
||||
c.gpClear = g.get("glClear")
|
||||
c.gpColorMask = g.get("glColorMask")
|
||||
c.gpCompileShader = g.get("glCompileShader")
|
||||
c.gpCreateProgram = g.get("glCreateProgram")
|
||||
c.gpCreateShader = g.get("glCreateShader")
|
||||
c.gpDeleteBuffers = g.get("glDeleteBuffers")
|
||||
c.gpDeleteFramebuffers = g.get("glDeleteFramebuffers")
|
||||
c.gpDeleteProgram = g.get("glDeleteProgram")
|
||||
c.gpDeleteRenderbuffers = g.get("glDeleteRenderbuffers")
|
||||
c.gpDeleteShader = g.get("glDeleteShader")
|
||||
c.gpDeleteTextures = g.get("glDeleteTextures")
|
||||
c.gpDeleteVertexArrays = g.get("glDeleteVertexArrays")
|
||||
c.gpDisable = g.get("glDisable")
|
||||
c.gpDisableVertexAttribArray = g.get("glDisableVertexAttribArray")
|
||||
c.gpDrawElements = g.get("glDrawElements")
|
||||
c.gpEnable = g.get("glEnable")
|
||||
c.gpEnableVertexAttribArray = g.get("glEnableVertexAttribArray")
|
||||
c.gpFlush = g.get("glFlush")
|
||||
c.gpFramebufferRenderbuffer = g.get("glFramebufferRenderbuffer")
|
||||
c.gpFramebufferTexture2D = g.get("glFramebufferTexture2D")
|
||||
c.gpGenBuffers = g.get("glGenBuffers")
|
||||
c.gpGenFramebuffers = g.get("glGenFramebuffers")
|
||||
c.gpGenRenderbuffers = g.get("glGenRenderbuffers")
|
||||
c.gpGenTextures = g.get("glGenTextures")
|
||||
c.gpGenVertexArrays = g.get("glGenVertexArrays")
|
||||
c.gpGetError = g.get("glGetError")
|
||||
c.gpGetIntegerv = g.get("glGetIntegerv")
|
||||
c.gpGetProgramInfoLog = g.get("glGetProgramInfoLog")
|
||||
c.gpGetProgramiv = g.get("glGetProgramiv")
|
||||
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")
|
||||
c.gpRenderbufferStorage = g.get("glRenderbufferStorage")
|
||||
c.gpScissor = g.get("glScissor")
|
||||
c.gpShaderSource = g.get("glShaderSource")
|
||||
c.gpStencilFunc = g.get("glStencilFunc")
|
||||
c.gpStencilOpSeparate = g.get("glStencilOpSeparate")
|
||||
c.gpTexImage2D = g.get("glTexImage2D")
|
||||
c.gpTexParameteri = g.get("glTexParameteri")
|
||||
c.gpTexSubImage2D = g.get("glTexSubImage2D")
|
||||
c.gpUniform1fv = g.get("glUniform1fv")
|
||||
c.gpUniform1i = g.get("glUniform1i")
|
||||
c.gpUniform1iv = g.get("glUniform1iv")
|
||||
c.gpUniform2fv = g.get("glUniform2fv")
|
||||
c.gpUniform2iv = g.get("glUniform2iv")
|
||||
c.gpUniform3fv = g.get("glUniform3fv")
|
||||
c.gpUniform3iv = g.get("glUniform3iv")
|
||||
c.gpUniform4fv = g.get("glUniform4fv")
|
||||
c.gpUniform4iv = g.get("glUniform4iv")
|
||||
c.gpUniformMatrix2fv = g.get("glUniformMatrix2fv")
|
||||
c.gpUniformMatrix3fv = g.get("glUniformMatrix3fv")
|
||||
c.gpUniformMatrix4fv = g.get("glUniformMatrix4fv")
|
||||
c.gpUseProgram = g.get("glUseProgram")
|
||||
c.gpVertexAttribPointer = g.get("glVertexAttribPointer")
|
||||
c.gpViewport = g.get("glViewport")
|
||||
|
||||
return g.error()
|
||||
}
|
||||
|
||||
// cStr takes a Go string (with or without null-termination)
|
||||
// and returns the C counterpart.
|
||||
//
|
||||
// The returned free function must be called once you are done using the string
|
||||
// in order to free the memory.
|
||||
func cStr(str string) (cstr *byte, free func()) {
|
||||
bs := []byte(str)
|
||||
if len(bs) == 0 || bs[len(bs)-1] != 0 {
|
||||
bs = append(bs, 0)
|
||||
}
|
||||
return &bs[0], func() {
|
||||
runtime.KeepAlive(bs)
|
||||
bs = nil
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
//go:build !playstation5
|
||||
|
||||
package gl
|
||||
|
||||
//go:generate go run gen.go
|
||||
//go:generate gofmt -s -w .
|
||||
|
||||
// Context is a context for OpenGL (ES) functions.
|
||||
//
|
||||
// Context is basically the same as gomobile's gl.Context.
|
||||
// See https://pkg.go.dev/github.com/ebitengine/gomobile/gl#Context
|
||||
type Context interface {
|
||||
LoadFunctions() error
|
||||
IsES() bool
|
||||
|
||||
ActiveTexture(texture uint32)
|
||||
AttachShader(program uint32, shader uint32)
|
||||
BindAttribLocation(program uint32, index uint32, name string)
|
||||
BindBuffer(target uint32, buffer uint32)
|
||||
BindFramebuffer(target uint32, framebuffer uint32)
|
||||
BindRenderbuffer(target uint32, renderbuffer uint32)
|
||||
BindTexture(target uint32, texture uint32)
|
||||
BindVertexArray(array uint32)
|
||||
BlendEquationSeparate(modeRGB uint32, modeAlpha uint32)
|
||||
BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32)
|
||||
BufferInit(target uint32, size int, usage uint32)
|
||||
BufferSubData(target uint32, offset int, data []byte)
|
||||
CheckFramebufferStatus(target uint32) uint32
|
||||
Clear(mask uint32)
|
||||
ColorMask(red, green, blue, alpha bool)
|
||||
CompileShader(shader uint32)
|
||||
CreateBuffer() uint32
|
||||
CreateFramebuffer() uint32
|
||||
CreateProgram() uint32
|
||||
CreateRenderbuffer() uint32
|
||||
CreateShader(xtype uint32) uint32
|
||||
CreateTexture() uint32
|
||||
CreateVertexArray() uint32
|
||||
DeleteBuffer(buffer uint32)
|
||||
DeleteFramebuffer(framebuffer uint32)
|
||||
DeleteProgram(program uint32)
|
||||
DeleteRenderbuffer(renderbuffer uint32)
|
||||
DeleteShader(shader uint32)
|
||||
DeleteTexture(texture uint32)
|
||||
DeleteVertexArray(array uint32)
|
||||
Disable(cap uint32)
|
||||
DisableVertexAttribArray(index uint32)
|
||||
DrawElements(mode uint32, count int32, xtype uint32, offset int)
|
||||
Enable(cap uint32)
|
||||
EnableVertexAttribArray(index uint32)
|
||||
Flush()
|
||||
FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32)
|
||||
FramebufferTexture2D(target uint32, attachment uint32, textarget uint32, texture uint32, level int32)
|
||||
GetError() uint32
|
||||
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)
|
||||
RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32)
|
||||
Scissor(x, y, width, height int32)
|
||||
ShaderSource(shader uint32, xstring string)
|
||||
StencilFunc(func_ uint32, ref int32, mask uint32)
|
||||
StencilOpSeparate(face, sfail, dpfail, dppass uint32)
|
||||
TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
||||
TexParameteri(target uint32, pname uint32, param int32)
|
||||
TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
||||
Uniform1fv(location int32, value []float32)
|
||||
Uniform1i(location int32, v0 int32)
|
||||
Uniform1iv(location int32, value []int32)
|
||||
Uniform2fv(location int32, value []float32)
|
||||
Uniform2iv(location int32, value []int32)
|
||||
Uniform3fv(location int32, value []float32)
|
||||
Uniform3iv(location int32, value []int32)
|
||||
Uniform4fv(location int32, value []float32)
|
||||
Uniform4iv(location int32, value []int32)
|
||||
UniformMatrix2fv(location int32, value []float32)
|
||||
UniformMatrix3fv(location int32, value []float32)
|
||||
UniformMatrix4fv(location int32, value []float32)
|
||||
UseProgram(program uint32)
|
||||
VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset int)
|
||||
Viewport(x int32, y int32, width int32, height int32)
|
||||
}
|
||||
Generated
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2023 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 !js && !playstation5
|
||||
|
||||
package gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type procAddressGetter struct {
|
||||
ctx *defaultContext
|
||||
err error
|
||||
}
|
||||
|
||||
func (p *procAddressGetter) get(name string) uintptr {
|
||||
proc, err := p.ctx.getProcAddress(name)
|
||||
if err != nil {
|
||||
p.err = fmt.Errorf("gl: %s is missing: %w", name, err)
|
||||
return 0
|
||||
}
|
||||
if proc == 0 {
|
||||
p.err = fmt.Errorf("gl: %s is missing", name)
|
||||
return 0
|
||||
}
|
||||
return proc
|
||||
}
|
||||
|
||||
func (p *procAddressGetter) error() error {
|
||||
return p.err
|
||||
}
|
||||
Generated
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
// Copyright 2022 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 gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
var (
|
||||
opengl uintptr
|
||||
)
|
||||
|
||||
func (c *defaultContext) init() error {
|
||||
lib, errGLES := purego.Dlopen("/System/Library/Frameworks/OpenGLES.framework/OpenGLES", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if errGLES == nil {
|
||||
c.isES = true
|
||||
opengl = lib
|
||||
return nil
|
||||
}
|
||||
|
||||
lib, errGL := purego.Dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if errGL == nil {
|
||||
opengl = lib
|
||||
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)
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(name string) (uintptr, error) {
|
||||
proc, err := purego.Dlsym(opengl, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return proc, nil
|
||||
}
|
||||
Generated
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
// Copyright 2022 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 (freebsd || linux || netbsd || openbsd) && !nintendosdk && !playstation5
|
||||
|
||||
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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
libGL unsafe.Pointer
|
||||
libGLES unsafe.Pointer
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("gl: failed to load libGL.so and libGLESv2.so")
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(name string) (uintptr, error) {
|
||||
if c.isES {
|
||||
return getProcAddressGLES(name), nil
|
||||
}
|
||||
return getProcAddressGL(name), nil
|
||||
}
|
||||
|
||||
func getProcAddressGL(name string) uintptr {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return uintptr(C.getProcAddressGL(libGL, cname))
|
||||
}
|
||||
|
||||
func getProcAddressGLES(name string) uintptr {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return uintptr(C.getProcAddressGLES(libGLES, cname))
|
||||
}
|
||||
Generated
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2022 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 nintendosdk
|
||||
|
||||
package gl
|
||||
|
||||
// #cgo LDFLAGS: -Wl,-unresolved-symbols=ignore-all
|
||||
//
|
||||
// #include <stdlib.h>
|
||||
// #include <EGL/egl.h>
|
||||
//
|
||||
// static void* getProcAddress(const char* name) {
|
||||
// return eglGetProcAddress(name);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (c *defaultContext) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(name string) (uintptr, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return uintptr(C.getProcAddress(cname)), nil
|
||||
}
|
||||
Generated
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 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 gl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
opengl32 = windows.NewLazySystemDLL("opengl32")
|
||||
procWglGetProcAddress = opengl32.NewProc("wglGetProcAddress")
|
||||
)
|
||||
|
||||
func (c *defaultContext) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *defaultContext) getProcAddress(namea string) (uintptr, error) {
|
||||
cname, err := windows.BytePtrFromString(namea)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
r, _, err := procWglGetProcAddress.Call(uintptr(unsafe.Pointer(cname)))
|
||||
if r != 0 {
|
||||
return r, nil
|
||||
}
|
||||
if err != nil && err != windows.ERROR_SUCCESS && err != windows.ERROR_PROC_NOT_FOUND {
|
||||
return 0, fmt.Errorf("gl: wglGetProcAddress failed for %s: %w", namea, err)
|
||||
}
|
||||
|
||||
p := opengl32.NewProc(namea)
|
||||
if err := p.Find(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return p.Addr(), nil
|
||||
}
|
||||
Generated
Vendored
+341
@@ -0,0 +1,341 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build !playstation5
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type activatedTexture struct {
|
||||
textureNative textureNative
|
||||
index int
|
||||
}
|
||||
|
||||
type Graphics struct {
|
||||
state openGLState
|
||||
context context
|
||||
vsync bool
|
||||
|
||||
nextImageID graphicsdriver.ImageID
|
||||
images map[graphicsdriver.ImageID]*Image
|
||||
|
||||
nextShaderID graphicsdriver.ShaderID
|
||||
shaders map[graphicsdriver.ShaderID]*Shader
|
||||
|
||||
// drawCalled is true just after Draw is called. This holds true until WritePixels is called.
|
||||
drawCalled bool
|
||||
|
||||
uniformVariableNameCache map[int]string
|
||||
textureVariableNameCache map[int]string
|
||||
|
||||
uniformVars []uniformVariable
|
||||
|
||||
// activatedTextures is a set of activated textures.
|
||||
// textureNative cannot be a map key unfortunately.
|
||||
activatedTextures []activatedTexture
|
||||
|
||||
graphicsPlatform
|
||||
}
|
||||
|
||||
func newGraphics(ctx gl.Context) *Graphics {
|
||||
g := &Graphics{
|
||||
vsync: true,
|
||||
}
|
||||
if isDebug {
|
||||
g.context.ctx = &gl.DebugContext{Context: ctx}
|
||||
} else {
|
||||
g.context.ctx = ctx
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Graphics) Begin() error {
|
||||
// Do nothing.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) End(present bool) error {
|
||||
// Call glFlush to prevent black flicking (especially on Android (#226) and iOS).
|
||||
// TODO: examples/sprites worked without this. Is this really needed?
|
||||
g.context.ctx.Flush()
|
||||
|
||||
// The last uniforms must be reset before swapping the buffer (#2517).
|
||||
if present {
|
||||
g.state.resetLastUniforms()
|
||||
if err := g.swapBuffers(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetTransparent(transparent bool) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
func (g *Graphics) checkSize(width, height int) {
|
||||
if width < 1 {
|
||||
panic(fmt.Sprintf("opengl: width (%d) must be equal or more than %d", width, 1))
|
||||
}
|
||||
if height < 1 {
|
||||
panic(fmt.Sprintf("opengl: height (%d) must be equal or more than %d", height, 1))
|
||||
}
|
||||
m := g.context.getMaxTextureSize()
|
||||
if width > m {
|
||||
panic(fmt.Sprintf("opengl: width (%d) must be less than or equal to %d", width, m))
|
||||
}
|
||||
if height > m {
|
||||
panic(fmt.Sprintf("opengl: height (%d) must be less than or equal to %d", height, m))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graphics) genNextImageID() graphicsdriver.ImageID {
|
||||
g.nextImageID++
|
||||
return g.nextImageID
|
||||
}
|
||||
|
||||
func (g *Graphics) genNextShaderID() graphicsdriver.ShaderID {
|
||||
g.nextShaderID++
|
||||
return g.nextShaderID
|
||||
}
|
||||
|
||||
func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
i := &Image{
|
||||
id: g.genNextImageID(),
|
||||
graphics: g,
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
w := graphics.InternalImageSize(width)
|
||||
h := graphics.InternalImageSize(height)
|
||||
g.checkSize(w, h)
|
||||
t, err := g.context.newTexture(w, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.texture = t
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) NewScreenFramebufferImage(width, height int) (graphicsdriver.Image, error) {
|
||||
g.checkSize(width, height)
|
||||
i := &Image{
|
||||
id: g.genNextImageID(),
|
||||
graphics: g,
|
||||
width: width,
|
||||
height: height,
|
||||
screen: true,
|
||||
}
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) addImage(img *Image) {
|
||||
if g.images == nil {
|
||||
g.images = map[graphicsdriver.ImageID]*Image{}
|
||||
}
|
||||
if _, ok := g.images[img.id]; ok {
|
||||
panic(fmt.Sprintf("opengl: image ID %d was already registered", img.id))
|
||||
}
|
||||
g.images[img.id] = img
|
||||
}
|
||||
|
||||
func (g *Graphics) removeImage(img *Image) {
|
||||
delete(g.images, img.id)
|
||||
}
|
||||
|
||||
func (g *Graphics) Initialize() error {
|
||||
if err := g.makeContextCurrent(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.state.reset(&g.context); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reset resets or initializes the current OpenGL state.
|
||||
func (g *Graphics) Reset() error {
|
||||
return g.state.reset(&g.context)
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVertices(vertices []float32, indices []uint32) error {
|
||||
g.state.setVertices(&g.context, vertices, indices)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) uniformVariableName(idx int) string {
|
||||
if v, ok := g.uniformVariableNameCache[idx]; ok {
|
||||
return v
|
||||
}
|
||||
if g.uniformVariableNameCache == nil {
|
||||
g.uniformVariableNameCache = map[int]string{}
|
||||
}
|
||||
name := fmt.Sprintf("U%d", idx)
|
||||
g.uniformVariableNameCache[idx] = name
|
||||
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 {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("opengl: shader ID is invalid")
|
||||
}
|
||||
|
||||
destination := g.images[dstID]
|
||||
|
||||
g.drawCalled = true
|
||||
|
||||
if err := destination.setViewport(); err != nil {
|
||||
return err
|
||||
}
|
||||
g.context.blend(blend)
|
||||
|
||||
shader := g.shaders[shaderID]
|
||||
program := shader.p
|
||||
|
||||
ulen := len(shader.ir.Uniforms)
|
||||
if cap(g.uniformVars) < ulen {
|
||||
g.uniformVars = make([]uniformVariable, ulen)
|
||||
} else {
|
||||
g.uniformVars = g.uniformVars[:ulen]
|
||||
}
|
||||
|
||||
var idx int
|
||||
for i, typ := range shader.ir.Uniforms {
|
||||
n := typ.Uint32Count()
|
||||
g.uniformVars[i].name = g.uniformVariableName(i)
|
||||
g.uniformVars[i].value = uniforms[idx : idx+n]
|
||||
g.uniformVars[i].typ = typ
|
||||
idx += n
|
||||
}
|
||||
|
||||
// In OpenGL, the NDC's Y direction is upward, so flip the Y direction for the final framebuffer.
|
||||
if destination.screen {
|
||||
const idx = graphics.ProjectionMatrixUniformVariableIndex
|
||||
// Invert the sign bits as float32 values.
|
||||
g.uniformVars[idx].value[1] ^= 1 << 31
|
||||
g.uniformVars[idx].value[5] ^= 1 << 31
|
||||
g.uniformVars[idx].value[9] ^= 1 << 31
|
||||
g.uniformVars[idx].value[13] ^= 1 << 31
|
||||
}
|
||||
|
||||
var imgs [graphics.ShaderImageCount]textureVariable
|
||||
for i, srcID := range srcIDs {
|
||||
if srcID == graphicsdriver.InvalidImageID {
|
||||
continue
|
||||
}
|
||||
imgs[i].valid = true
|
||||
imgs[i].native = g.images[srcID].texture
|
||||
}
|
||||
|
||||
if err := g.useProgram(program, g.uniformVars, imgs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range g.uniformVars {
|
||||
g.uniformVars[i] = uniformVariable{}
|
||||
}
|
||||
g.uniformVars = g.uniformVars[:0]
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
if err := destination.ensureStencilBuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
g.context.ctx.Enable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.context.ctx.Scissor(
|
||||
int32(dstRegion.Region.Min.X),
|
||||
int32(dstRegion.Region.Min.Y),
|
||||
int32(dstRegion.Region.Dx()),
|
||||
int32(dstRegion.Region.Dy()),
|
||||
)
|
||||
switch fillRule {
|
||||
case graphicsdriver.NonZero:
|
||||
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:
|
||||
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)
|
||||
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))))
|
||||
}
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
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)
|
||||
}
|
||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
if fillRule != graphicsdriver.FillAll {
|
||||
g.context.ctx.Disable(gl.STENCIL_TEST)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
||||
g.vsync = enabled
|
||||
}
|
||||
|
||||
func (g *Graphics) NeedsClearingScreen() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *Graphics) MaxImageSize() int {
|
||||
return g.context.getMaxTextureSize()
|
||||
}
|
||||
|
||||
func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
s, err := newShader(g.genNextShaderID(), g, program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.addShader(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) addShader(shader *Shader) {
|
||||
if g.shaders == nil {
|
||||
g.shaders = map[graphicsdriver.ShaderID]*Shader{}
|
||||
}
|
||||
if _, ok := g.shaders[shader.id]; ok {
|
||||
panic(fmt.Sprintf("opengl: shader ID %d was already registered", shader.id))
|
||||
}
|
||||
g.shaders[shader.id] = shader
|
||||
}
|
||||
|
||||
func (g *Graphics) removeShader(shader *Shader) {
|
||||
delete(g.shaders, shader.id)
|
||||
}
|
||||
Generated
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2023 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 ebitenginegldebug
|
||||
|
||||
package opengl
|
||||
|
||||
const isDebug = true
|
||||
Generated
Vendored
+119
@@ -0,0 +1,119 @@
|
||||
// Copyright 2022 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 !android && !ios && !js && !nintendosdk && !playstation5
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"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 := setGLFWClientAPI(ctx.IsES()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newGraphics(ctx), nil
|
||||
}
|
||||
|
||||
func setGLFWClientAPI(isES bool) error {
|
||||
if isES {
|
||||
if err := glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLESAPI); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMajor, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMinor, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextCreationAPI, glfw.EGLContextAPI); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLAPI); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := glfw.WindowHint(glfw.ContextVersionMajor, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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 := glfw.SwapInterval(1); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := glfw.SwapInterval(0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.window.SwapBuffers(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright 2022 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"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
)
|
||||
|
||||
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) {
|
||||
var glContext js.Value
|
||||
|
||||
attr := js.Global().Get("Object").New()
|
||||
attr.Set("alpha", true)
|
||||
attr.Set("premultipliedAlpha", true)
|
||||
attr.Set("stencil", true)
|
||||
|
||||
glContext = canvas.Call("getContext", "webgl2", attr)
|
||||
|
||||
if !glContext.Truthy() {
|
||||
return nil, fmt.Errorf("opengl: getContext for webgl2 failed")
|
||||
}
|
||||
|
||||
ctx, err := gl.NewDefaultContext(glContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newGraphics(ctx), nil
|
||||
}
|
||||
|
||||
func (g *Graphics) makeContextCurrent() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) swapBuffers() error {
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build android || ios
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
)
|
||||
|
||||
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) {
|
||||
ctx, err := gl.NewDefaultContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newGraphics(ctx), nil
|
||||
}
|
||||
|
||||
func (g *Graphics) makeContextCurrent() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) swapBuffers() error {
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
// Copyright 2023 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 nintendosdk
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
)
|
||||
|
||||
type graphicsPlatform struct {
|
||||
egl *egl
|
||||
}
|
||||
|
||||
func NewGraphics(nativeWindowType uintptr) (graphicsdriver.Graphics, error) {
|
||||
ctx, err := gl.NewDefaultContext()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g := newGraphics(ctx)
|
||||
e, err := newEGL(nativeWindowType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.egl = e
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) makeContextCurrent() error {
|
||||
return g.egl.makeContextCurrent()
|
||||
}
|
||||
|
||||
func (g *Graphics) swapBuffers() error {
|
||||
g.egl.swapBuffers()
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2023 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 !ebitenginegldebug
|
||||
|
||||
package opengl
|
||||
|
||||
const isDebug = false
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build !playstation5
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
id graphicsdriver.ImageID
|
||||
graphics *Graphics
|
||||
texture textureNative
|
||||
stencil renderbufferNative
|
||||
framebuffer *framebuffer
|
||||
width int
|
||||
height int
|
||||
screen bool
|
||||
}
|
||||
|
||||
// framebuffer is a wrapper of OpenGL's framebuffer.
|
||||
type framebuffer struct {
|
||||
graphics *Graphics
|
||||
native framebufferNative
|
||||
width int
|
||||
height int
|
||||
}
|
||||
|
||||
func (i *Image) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *Image) Dispose() {
|
||||
if i.framebuffer != nil {
|
||||
i.graphics.context.deleteFramebuffer(i.framebuffer.native)
|
||||
}
|
||||
if i.texture != 0 {
|
||||
i.graphics.context.deleteTexture(i.texture)
|
||||
}
|
||||
if i.stencil != 0 {
|
||||
i.graphics.context.deleteRenderbuffer(i.stencil)
|
||||
}
|
||||
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *Image) setViewport() error {
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
i.graphics.context.setViewport(i.framebuffer)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, arg := range args {
|
||||
if err := i.graphics.context.framebufferPixels(arg.Pixels, i.framebuffer, arg.Region); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) framebufferSize() (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
|
||||
// Edge can't treat a bigger viewport than the drawing area (#71).
|
||||
return i.width, i.height
|
||||
}
|
||||
return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||
}
|
||||
|
||||
func (i *Image) ensureFramebuffer() error {
|
||||
if i.framebuffer != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
w, h := i.framebufferSize()
|
||||
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
|
||||
}
|
||||
i.framebuffer = f
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) ensureStencilBuffer() error {
|
||||
if i.stencil != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := i.ensureFramebuffer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := i.graphics.context.newRenderbuffer(i.framebufferSize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencil = r
|
||||
|
||||
if err := i.graphics.context.bindStencilBuffer(i.framebuffer.native, i.stencil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
if i.screen {
|
||||
return errors.New("opengl: WritePixels cannot be called on the screen")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// glFlush is necessary on Android.
|
||||
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
|
||||
if i.graphics.drawCalled {
|
||||
i.graphics.context.ctx.Flush()
|
||||
}
|
||||
i.graphics.drawCalled = false
|
||||
|
||||
i.graphics.context.bindTexture(i.texture)
|
||||
for _, a := range args {
|
||||
x := int32(a.Region.Min.X)
|
||||
y := int32(a.Region.Min.Y)
|
||||
width := int32(a.Region.Dx())
|
||||
height := int32(a.Region.Dy())
|
||||
i.graphics.context.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2014 Hajime Hoshi
|
||||
//
|
||||
// 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 opengl
|
||||
|
||||
type locationCache struct {
|
||||
uniformLocationCache map[program]map[string]uniformLocation
|
||||
}
|
||||
|
||||
func newLocationCache() *locationCache {
|
||||
return &locationCache{
|
||||
uniformLocationCache: map[program]map[string]uniformLocation{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *locationCache) GetUniformLocation(context *context, p program, location string) uniformLocation {
|
||||
if _, ok := c.uniformLocationCache[p]; !ok {
|
||||
c.uniformLocationCache[p] = map[string]uniformLocation{}
|
||||
}
|
||||
l, ok := c.uniformLocationCache[p][location]
|
||||
if !ok {
|
||||
l = uniformLocation(context.ctx.GetUniformLocation(uint32(p), location))
|
||||
c.uniformLocationCache[p][location] = l
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (c *locationCache) deleteProgram(p program) {
|
||||
delete(c.uniformLocationCache, p)
|
||||
}
|
||||
Generated
Vendored
+344
@@ -0,0 +1,344 @@
|
||||
// Copyright 2014 Hajime Hoshi
|
||||
//
|
||||
// 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 opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
const floatSizeInBytes = 4
|
||||
|
||||
// arrayBufferLayoutPart is a part of an array buffer layout.
|
||||
type arrayBufferLayoutPart struct {
|
||||
// TODO: This struct should belong to a program and know it.
|
||||
name string
|
||||
num int
|
||||
}
|
||||
|
||||
// arrayBufferLayout is an array buffer layout.
|
||||
//
|
||||
// An array buffer in OpenGL is a buffer representing vertices and
|
||||
// is passed to a vertex shader.
|
||||
type arrayBufferLayout struct {
|
||||
parts []arrayBufferLayoutPart
|
||||
total int
|
||||
}
|
||||
|
||||
func (a *arrayBufferLayout) names() []string {
|
||||
ns := make([]string, len(a.parts))
|
||||
for i, p := range a.parts {
|
||||
ns[i] = p.name
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// totalBytes returns the size in bytes for one element of the array buffer.
|
||||
func (a *arrayBufferLayout) totalBytes() int {
|
||||
if a.total != 0 {
|
||||
return a.total
|
||||
}
|
||||
t := 0
|
||||
for _, p := range a.parts {
|
||||
t += floatSizeInBytes * p.num
|
||||
}
|
||||
a.total = t
|
||||
return a.total
|
||||
}
|
||||
|
||||
// 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()
|
||||
offset := 0
|
||||
for i, p := range a.parts {
|
||||
context.ctx.VertexAttribPointer(uint32(i), int32(p.num), gl.FLOAT, false, int32(total), offset)
|
||||
offset += floatSizeInBytes * p.num
|
||||
}
|
||||
}
|
||||
|
||||
// disable stops using the array buffer.
|
||||
func (a *arrayBufferLayout) disable(context *context) {
|
||||
// TODO: Disabling should be done in reversed order?
|
||||
for i := range a.parts {
|
||||
context.ctx.DisableVertexAttribArray(uint32(i))
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
vertexFloatCount := theArrayBufferLayout.totalBytes() / floatSizeInBytes
|
||||
if graphics.VertexFloatCount != vertexFloatCount {
|
||||
panic(fmt.Sprintf("vertex float num must be %d but %d", graphics.VertexFloatCount, vertexFloatCount))
|
||||
}
|
||||
}
|
||||
|
||||
type openGLState struct {
|
||||
vertexArray uint32
|
||||
|
||||
// arrayBuffer is OpenGL's array buffer (vertices data).
|
||||
arrayBuffer buffer
|
||||
|
||||
arrayBufferSizeInBytes int
|
||||
|
||||
// elementArrayBuffer is OpenGL's element array buffer (indices data).
|
||||
elementArrayBuffer buffer
|
||||
|
||||
elementArrayBufferSizeInBytes int
|
||||
|
||||
lastProgram program
|
||||
lastUniforms map[string][]uint32
|
||||
lastActiveTexture int
|
||||
}
|
||||
|
||||
// reset resets or initializes the OpenGL state.
|
||||
func (s *openGLState) reset(context *context) error {
|
||||
if err := context.reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.lastProgram = 0
|
||||
context.ctx.UseProgram(0)
|
||||
for key := range s.lastUniforms {
|
||||
delete(s.lastUniforms, key)
|
||||
}
|
||||
|
||||
// On browsers (at least Chrome), buffers are already detached from the context
|
||||
// and must not be deleted by DeleteBuffer.
|
||||
if runtime.GOOS != "js" {
|
||||
if s.arrayBuffer != 0 {
|
||||
context.ctx.DeleteBuffer(uint32(s.arrayBuffer))
|
||||
}
|
||||
if s.elementArrayBuffer != 0 {
|
||||
context.ctx.DeleteBuffer(uint32(s.elementArrayBuffer))
|
||||
}
|
||||
if s.vertexArray != 0 {
|
||||
context.ctx.DeleteVertexArray(s.vertexArray)
|
||||
}
|
||||
}
|
||||
|
||||
s.arrayBuffer = 0
|
||||
s.arrayBufferSizeInBytes = 0
|
||||
s.elementArrayBuffer = 0
|
||||
s.elementArrayBufferSizeInBytes = 0
|
||||
s.vertexArray = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pow2(x int) int {
|
||||
if x > (math.MaxInt+1)/2 {
|
||||
return math.MaxInt
|
||||
}
|
||||
|
||||
p2 := 1
|
||||
for p2 < x {
|
||||
p2 *= 2
|
||||
}
|
||||
return p2
|
||||
}
|
||||
|
||||
func (s *openGLState) setVertices(context *context, vertices []float32, indices []uint32) {
|
||||
if s.vertexArray == 0 {
|
||||
s.vertexArray = context.ctx.CreateVertexArray()
|
||||
}
|
||||
context.ctx.BindVertexArray(s.vertexArray)
|
||||
|
||||
if size := len(vertices) * int(unsafe.Sizeof(vertices[0])); s.arrayBufferSizeInBytes < size {
|
||||
if s.arrayBuffer != 0 {
|
||||
context.ctx.DeleteBuffer(uint32(s.arrayBuffer))
|
||||
}
|
||||
|
||||
newSize := pow2(size)
|
||||
// newArrayBuffer calls BindBuffer.
|
||||
s.arrayBuffer = context.newArrayBuffer(newSize)
|
||||
s.arrayBufferSizeInBytes = newSize
|
||||
|
||||
// Reenable the array buffer layout explicitly after resetting the array buffer.
|
||||
theArrayBufferLayout.enable(context)
|
||||
}
|
||||
|
||||
if size := len(indices) * int(unsafe.Sizeof(indices[0])); s.elementArrayBufferSizeInBytes < size {
|
||||
if s.elementArrayBuffer != 0 {
|
||||
context.ctx.DeleteBuffer(uint32(s.elementArrayBuffer))
|
||||
}
|
||||
|
||||
newSize := pow2(size)
|
||||
// newElementArrayBuffer calls BindBuffer.
|
||||
s.elementArrayBuffer = context.newElementArrayBuffer(newSize)
|
||||
s.elementArrayBufferSizeInBytes = newSize
|
||||
}
|
||||
|
||||
// Note that the vertices and the indices passed to BufferSubData is not under GC management in the gl package.
|
||||
vs := unsafe.Slice((*byte)(unsafe.Pointer(&vertices[0])), len(vertices)*int(unsafe.Sizeof(vertices[0])))
|
||||
context.ctx.BufferSubData(gl.ARRAY_BUFFER, 0, vs)
|
||||
is := unsafe.Slice((*byte)(unsafe.Pointer(&indices[0])), len(indices)*int(unsafe.Sizeof(indices[0])))
|
||||
context.ctx.BufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, is)
|
||||
}
|
||||
|
||||
func (s *openGLState) resetLastUniforms() {
|
||||
for k := range s.lastUniforms {
|
||||
delete(s.lastUniforms, k)
|
||||
}
|
||||
}
|
||||
|
||||
// areSameUint32Array returns a boolean indicating if a and b are deeply equal.
|
||||
func areSameUint32Array(a, b []uint32) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type uniformVariable struct {
|
||||
name string
|
||||
value []uint32
|
||||
typ shaderir.Type
|
||||
}
|
||||
|
||||
type textureVariable struct {
|
||||
valid bool
|
||||
native textureNative
|
||||
}
|
||||
|
||||
func (g *Graphics) textureVariableName(idx int) string {
|
||||
if v, ok := g.textureVariableNameCache[idx]; ok {
|
||||
return v
|
||||
}
|
||||
if g.textureVariableNameCache == nil {
|
||||
g.textureVariableNameCache = map[int]string{}
|
||||
}
|
||||
name := fmt.Sprintf("T%d", idx)
|
||||
g.textureVariableNameCache[idx] = name
|
||||
return name
|
||||
}
|
||||
|
||||
// useProgram uses the program (programTexture).
|
||||
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderImageCount]textureVariable) error {
|
||||
if g.state.lastProgram != program {
|
||||
g.context.ctx.UseProgram(uint32(program))
|
||||
|
||||
g.state.lastProgram = program
|
||||
for k := range g.state.lastUniforms {
|
||||
delete(g.state.lastUniforms, k)
|
||||
}
|
||||
g.state.lastActiveTexture = 0
|
||||
g.context.ctx.ActiveTexture(gl.TEXTURE0)
|
||||
g.context.lastTexture = 0 // Make sure next bindTexture call actually does something.
|
||||
}
|
||||
|
||||
for _, u := range uniforms {
|
||||
if u.value == nil {
|
||||
continue
|
||||
}
|
||||
if got, expected := len(u.value), u.typ.Uint32Count(); 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
|
||||
return fmt.Errorf("opengl: length of a uniform variables %s (%s) doesn't match: expected %d but %d", u.name, typ.String(), expected, got)
|
||||
}
|
||||
|
||||
cached, ok := g.state.lastUniforms[u.name]
|
||||
if ok && areSameUint32Array(cached, u.value) {
|
||||
continue
|
||||
}
|
||||
g.context.uniforms(program, u.name, u.value, u.typ)
|
||||
if g.state.lastUniforms == nil {
|
||||
g.state.lastUniforms = map[string][]uint32{}
|
||||
}
|
||||
g.state.lastUniforms[u.name] = u.value
|
||||
}
|
||||
|
||||
var idx int
|
||||
loop:
|
||||
for i, t := range textures {
|
||||
if !t.valid {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the texture is already bound, set the texture variable to point to the texture.
|
||||
// Rebinding the same texture seems problematic (#1193).
|
||||
for _, at := range g.activatedTextures {
|
||||
if t.native == at.textureNative {
|
||||
g.context.uniformInt(program, g.textureVariableName(i), at.index)
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
g.activatedTextures = append(g.activatedTextures, activatedTexture{
|
||||
textureNative: t.native,
|
||||
index: idx,
|
||||
})
|
||||
g.context.uniformInt(program, g.textureVariableName(i), idx)
|
||||
if g.state.lastActiveTexture != idx {
|
||||
g.context.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
|
||||
g.state.lastActiveTexture = idx
|
||||
g.context.lastTexture = 0 // Make sure next bindTexture call actually does something.
|
||||
}
|
||||
|
||||
// Apparently, a texture must be bound every time. The cache is not used here.
|
||||
g.context.bindTexture(t.native)
|
||||
|
||||
idx++
|
||||
}
|
||||
|
||||
for i := range g.activatedTextures {
|
||||
g.activatedTextures[i] = activatedTexture{}
|
||||
}
|
||||
g.activatedTextures = g.activatedTextures[:0]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func uint32sToFloat32s(s []uint32) []float32 {
|
||||
return unsafe.Slice((*float32)(unsafe.Pointer(&s[0])), len(s))
|
||||
}
|
||||
|
||||
func uint32sToInt32s(s []uint32) []int32 {
|
||||
return unsafe.Slice((*int32)(unsafe.Pointer(&s[0])), len(s))
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
//go:build !playstation5
|
||||
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/glsl"
|
||||
)
|
||||
|
||||
type Shader struct {
|
||||
id graphicsdriver.ShaderID
|
||||
graphics *Graphics
|
||||
|
||||
ir *shaderir.Program
|
||||
p program
|
||||
}
|
||||
|
||||
func newShader(id graphicsdriver.ShaderID, graphics *Graphics, program *shaderir.Program) (*Shader, error) {
|
||||
s := &Shader{
|
||||
id: id,
|
||||
graphics: graphics,
|
||||
ir: program,
|
||||
}
|
||||
if err := s.compile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Shader) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *Shader) Dispose() {
|
||||
s.graphics.context.deleteProgram(s.p)
|
||||
s.graphics.removeShader(s)
|
||||
}
|
||||
|
||||
func (s *Shader) compile() error {
|
||||
vssrc, fssrc := glsl.Compile(s.ir, s.graphics.context.glslVersion())
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
defer s.graphics.context.ctx.DeleteShader(uint32(fs))
|
||||
|
||||
p, err := s.graphics.context.newProgram([]shader{vs, fs}, theArrayBufferLayout.names())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.p = p
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2023 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
|
||||
|
||||
// The actual implementation will be provided by -overlay.
|
||||
|
||||
#include "graphics_playstation5.h"
|
||||
|
||||
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_NewScreenFramebufferImage(int* image, int width, int height) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" void ebitengine_DisposeImage(int id) {
|
||||
}
|
||||
|
||||
extern "C" ebitengine_Error ebitengine_NewShader(int* shader, const char* source) {
|
||||
return {};
|
||||
}
|
||||
|
||||
extern "C" void ebitengine_DisposeShader(int id) {
|
||||
}
|
||||
Generated
Vendored
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright 2023 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
|
||||
|
||||
// #include "graphics_playstation5.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type playstation5Error struct {
|
||||
name string
|
||||
code int
|
||||
message string
|
||||
}
|
||||
|
||||
func newPlaystation5Error(name string, err C.ebitengine_Error) *playstation5Error {
|
||||
return &playstation5Error{
|
||||
name: name,
|
||||
code: int(err.code),
|
||||
message: C.GoString(err.message),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *playstation5Error) Error() string {
|
||||
return fmt.Sprintf("playstation5: error at %s, code: %d, message: %s", e.name, e.code, e.message)
|
||||
}
|
||||
|
||||
type Graphics struct {
|
||||
}
|
||||
|
||||
func NewGraphics() (*Graphics, error) {
|
||||
return &Graphics{}, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) Initialize() error {
|
||||
if err := C.ebitengine_InitializeGraphics(); !C.ebitengine_IsErrorNil(&err) {
|
||||
return newPlaystation5Error("(*playstation5.Graphics).Initialize", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) Begin() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) End(present bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetTransparent(transparent bool) {
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVertices(vertices []float32, indices []uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
var id C.int
|
||||
if err := C.ebitengine_NewImage(&id, C.int(width), C.int(height)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return nil, newPlaystation5Error("(*playstation5.Graphics).NewImage", err)
|
||||
}
|
||||
return &Image{
|
||||
id: graphicsdriver.ImageID(id),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) NewScreenFramebufferImage(width, height int) (graphicsdriver.Image, error) {
|
||||
var id C.int
|
||||
if err := C.ebitengine_NewScreenFramebufferImage(&id, C.int(width), C.int(height)); !C.ebitengine_IsErrorNil(&err) {
|
||||
return nil, newPlaystation5Error("(*playstation5.Graphics).NewScreenFramebufferImage", err)
|
||||
}
|
||||
return &Image{
|
||||
id: graphicsdriver.ImageID(id),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) SetVsyncEnabled(enabled bool) {
|
||||
}
|
||||
|
||||
func (g *Graphics) NeedsClearingScreen() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *Graphics) MaxImageSize() int {
|
||||
return 4096 // TODO: Get the value from the SDK.
|
||||
}
|
||||
|
||||
func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
var id C.int
|
||||
// TODO: Give a source code.
|
||||
if err := C.ebitengine_NewShader(&id, nil); !C.ebitengine_IsErrorNil(&err) {
|
||||
return nil, newPlaystation5Error("(*playstation5.Graphics).NewShader", err)
|
||||
}
|
||||
return &Shader{
|
||||
id: graphicsdriver.ShaderID(id),
|
||||
}, 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 {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
id graphicsdriver.ImageID
|
||||
}
|
||||
|
||||
func (i *Image) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *Image) Dispose() {
|
||||
C.ebitengine_DisposeImage(C.int(i.id))
|
||||
}
|
||||
|
||||
func (i *Image) ReadPixels(args []graphicsdriver.PixelsArgs) error {
|
||||
// TODO: Implement this
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Image) WritePixels(args []graphicsdriver.PixelsArgs) error {
|
||||
// TODO: Implement this
|
||||
return nil
|
||||
}
|
||||
|
||||
type Shader struct {
|
||||
id graphicsdriver.ShaderID
|
||||
}
|
||||
|
||||
func (s *Shader) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *Shader) Dispose() {
|
||||
C.ebitengine_DisposeShader(C.int(s.id))
|
||||
}
|
||||
vendor/github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/playstation5/graphics_playstation5.h
Generated
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2023 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
|
||||
|
||||
#ifndef EBITENGINE_INTERNAL_GRAPHICSDRIVER_PLAYSTATION5_GRAPHICS_PLAYSTATION5_H
|
||||
#define EBITENGINE_INTERNAL_GRAPHICSDRIVER_PLAYSTATION5_GRAPHICS_PLAYSTATION5_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ebitengine_Error {
|
||||
const char* message;
|
||||
int code;
|
||||
} ebitengine_Error;
|
||||
|
||||
static bool ebitengine_IsErrorNil(ebitengine_Error* err) {
|
||||
return err->message == NULL && err->code == 0;
|
||||
}
|
||||
|
||||
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);
|
||||
void ebitengine_DisposeImage(int id);
|
||||
|
||||
ebitengine_Error ebitengine_NewShader(int* shader, const char* source);
|
||||
void ebitengine_DisposeShader(int id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // EBITENGINE_INTERNAL_GRAPHICSDRIVER_PLAYSTATION5_GRAPHICS_PLAYSTATION5_H
|
||||
Reference in New Issue
Block a user