D3D12: Initial commit.

This commit is contained in:
Branimir Karadžić 2015-07-29 19:38:17 -07:00
parent 5f466bd576
commit b702dcdf3c
10 changed files with 9142 additions and 2 deletions

View file

@ -17,4 +17,7 @@
#include "renderer_null.cpp"
#include "renderer_gl.cpp"
#include "renderer_vk.cpp"
#include "shader_dxbc.cpp"
#include "shader_dx9bc.cpp"
#include "shader_spirv.cpp"
#include "vertexdecl.cpp"

View file

@ -140,11 +140,13 @@ namespace bgfx
# include <tinystl/string.h>
# include <tinystl/unordered_map.h>
# include <tinystl/unordered_set.h>
# include <tinystl/vector.h>
namespace stl = tinystl;
#else
# include <string>
# include <unordered_map>
# include <unordered_set>
# include <vector>
namespace stl
{
using namespace std;

File diff suppressed because it is too large Load diff

430
src/renderer_d3d12.h Normal file
View file

@ -0,0 +1,430 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#ifndef BGFX_RENDERER_D3D12_H_HEADER_GUARD
#define BGFX_RENDERER_D3D12_H_HEADER_GUARD
#define USE_D3D12_DYNAMIC_LIB 1
#include <d3d12.h>
#include <d3dx12.h>
#include <dxgidebug.h>
#include "renderer.h"
#include "renderer_d3d.h"
#include "shader_dxbc.h"
namespace bgfx { namespace d3d12
{
struct Rdt
{
enum Enum
{
Sampler,
SRV,
CBV,
UAV,
Count
};
};
class ScratchBufferD3D12
{
public:
ScratchBufferD3D12()
{
}
~ScratchBufferD3D12()
{
}
void create(uint32_t _size, uint32_t _maxDescriptors);
void destroy();
void reset(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle);
void* alloc(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle, uint32_t _size);
void alloc(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle, struct TextureD3D12& _texture);
void allocUav(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle, struct TextureD3D12& _texture);
void alloc(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle, struct BufferD3D12& _buffer);
void allocUav(D3D12_GPU_DESCRIPTOR_HANDLE& gpuHandle, struct BufferD3D12& _buffer);
ID3D12DescriptorHeap* getHeap()
{
return m_heap;
}
private:
ID3D12DescriptorHeap* m_heap;
ID3D12Resource* m_upload;
D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle;
D3D12_GPU_DESCRIPTOR_HANDLE m_gpuHandle;
uint32_t m_incrementSize;
uint8_t* m_data;
uint32_t m_size;
uint32_t m_pos;
};
class DescriptorAllocator
{
public:
DescriptorAllocator()
: m_numDescriptorsPerBlock(1)
{
}
~DescriptorAllocator()
{
}
void create(D3D12_DESCRIPTOR_HEAP_TYPE _type, uint32_t _maxDescriptors, uint16_t _numDescriptorsPerBlock = 1);
void destroy();
uint16_t alloc(ID3D12Resource* _ptr, const D3D12_SHADER_RESOURCE_VIEW_DESC* _desc);
uint16_t alloc(const uint32_t* _flags, uint32_t _num = BGFX_CONFIG_MAX_TEXTURE_SAMPLERS);
void free(uint16_t _handle);
D3D12_GPU_DESCRIPTOR_HANDLE get(uint16_t _handle);
ID3D12DescriptorHeap* getHeap()
{
return m_heap;
}
private:
ID3D12DescriptorHeap* m_heap;
bx::HandleAlloc* m_handleAlloc;
D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle;
D3D12_GPU_DESCRIPTOR_HANDLE m_gpuHandle;
uint32_t m_incrementSize;
uint16_t m_numDescriptorsPerBlock;
};
struct BufferD3D12
{
BufferD3D12()
: m_ptr(NULL)
, m_staging(NULL)
, m_state(D3D12_RESOURCE_STATE_COMMON)
, m_size(0)
, m_flags(BGFX_BUFFER_NONE)
, m_dynamic(false)
{
}
void create(uint32_t _size, void* _data, uint16_t _flags, bool _vertex);
void update(ID3D12GraphicsCommandList* _commandList, uint32_t _offset, uint32_t _size, void* _data, bool _discard = false);
void destroy()
{
if (NULL != m_ptr)
{
DX_RELEASE(m_ptr, 0);
DX_RELEASE(m_staging, 0);
m_dynamic = false;
}
}
void setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state);
D3D12_SHADER_RESOURCE_VIEW_DESC m_srvd;
D3D12_UNORDERED_ACCESS_VIEW_DESC m_uavd;
ID3D12Resource* m_ptr;
ID3D12Resource* m_staging;
D3D12_RESOURCE_STATES m_state;
uint32_t m_size;
uint16_t m_flags;
bool m_dynamic;
};
struct VertexBufferD3D12 : public BufferD3D12
{
void create(uint32_t _size, void* _data, VertexDeclHandle _declHandle, uint16_t _flags);
VertexDeclHandle m_decl;
};
struct ShaderD3D12
{
ShaderD3D12()
: m_code(NULL)
, m_constantBuffer(NULL)
, m_hash(0)
, m_numUniforms(0)
, m_numPredefined(0)
{
}
void create(const Memory* _mem);
DWORD* getShaderCode(uint8_t _fragmentBit, const Memory* _mem);
void destroy()
{
if (NULL != m_constantBuffer)
{
ConstantBuffer::destroy(m_constantBuffer);
m_constantBuffer = NULL;
}
m_numPredefined = 0;
if (NULL != m_code)
{
release(m_code);
m_code = NULL;
m_hash = 0;
}
}
const Memory* m_code;
ConstantBuffer* m_constantBuffer;
PredefinedUniform m_predefined[PredefinedUniform::Count];
uint8_t m_attrMask[Attrib::Count];
uint32_t m_hash;
uint16_t m_numUniforms;
uint16_t m_size;
uint8_t m_numPredefined;
};
struct ProgramD3D12
{
ProgramD3D12()
: m_vsh(NULL)
, m_fsh(NULL)
{
}
void create(const ShaderD3D12* _vsh, const ShaderD3D12* _fsh)
{
BX_CHECK(NULL != _vsh->m_code, "Vertex shader doesn't exist.");
m_vsh = _vsh;
memcpy(&m_predefined[0], _vsh->m_predefined, _vsh->m_numPredefined*sizeof(PredefinedUniform));
m_numPredefined = _vsh->m_numPredefined;
if (NULL != _fsh)
{
BX_CHECK(NULL != _fsh->m_code, "Fragment shader doesn't exist.");
m_fsh = _fsh;
memcpy(&m_predefined[m_numPredefined], _fsh->m_predefined, _fsh->m_numPredefined*sizeof(PredefinedUniform));
m_numPredefined += _fsh->m_numPredefined;
}
}
void destroy()
{
m_numPredefined = 0;
m_vsh = NULL;
m_fsh = NULL;
}
const ShaderD3D12* m_vsh;
const ShaderD3D12* m_fsh;
PredefinedUniform m_predefined[PredefinedUniform::Count * 2];
uint8_t m_numPredefined;
};
struct TextureD3D12
{
enum Enum
{
Texture2D,
Texture3D,
TextureCube,
};
TextureD3D12()
: m_ptr(NULL)
, m_staging(NULL)
, m_state(D3D12_RESOURCE_STATE_COMMON)
, m_numMips(0)
{
}
void create(const Memory* _mem, uint32_t _flags, uint8_t _skip);
void destroy();
void update(ID3D12GraphicsCommandList* _commandList, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
void resolve();
void setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state);
D3D12_SHADER_RESOURCE_VIEW_DESC m_srvd;
D3D12_UNORDERED_ACCESS_VIEW_DESC m_uavd;
ID3D12Resource* m_ptr;
ID3D12Resource* m_staging;
D3D12_RESOURCE_STATES m_state;
uint32_t m_flags;
uint16_t m_samplerIdx;
uint8_t m_type;
uint8_t m_requestedFormat;
uint8_t m_textureFormat;
uint8_t m_numMips;
};
struct FrameBufferD3D12
{
FrameBufferD3D12()
: m_swapChain(NULL)
, m_denseIdx(UINT16_MAX)
, m_num(0)
, m_numTh(0)
{
m_depth.idx = bgfx::invalidHandle;
}
void create(uint8_t _num, const TextureHandle* _handles);
void create(uint16_t _denseIdx, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _depthFormat);
uint16_t destroy();
void preReset();
void postReset();
void resolve();
void clear(ID3D12GraphicsCommandList* _commandList, const Clear& _clear, const float _palette[][4], const D3D12_RECT* _rect = NULL, uint32_t _num = 0);
TextureHandle m_texture[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
TextureHandle m_depth;
IDXGISwapChain* m_swapChain;
uint16_t m_denseIdx;
uint8_t m_num;
uint8_t m_numTh;
TextureHandle m_th[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
};
struct CommandQueue
{
CommandQueue()
: m_control(BX_COUNTOF(m_commandList) )
{
}
void init(ID3D12Device* _device)
{
D3D12_COMMAND_QUEUE_DESC queueDesc;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Priority = 0;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
DX_CHECK(_device->CreateCommandQueue(&queueDesc
, __uuidof(ID3D12CommandQueue)
, (void**)&m_commandQueue
) );
m_currentFence = 0;
DX_CHECK(_device->CreateFence(0
, D3D12_FENCE_FLAG_NONE
, __uuidof(ID3D12Fence)
, (void**)&m_fence
) );
for (uint32_t ii = 0; ii < BX_COUNTOF(m_commandList); ++ii)
{
DX_CHECK(_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT
, __uuidof(ID3D12CommandAllocator)
, (void**)&m_commandList[ii].m_commandAllocator
) );
DX_CHECK(_device->CreateCommandList(0
, D3D12_COMMAND_LIST_TYPE_DIRECT
, m_commandList[ii].m_commandAllocator
, NULL
, __uuidof(ID3D12GraphicsCommandList)
, (void**)&m_commandList[ii].m_commandList
) );
DX_CHECK(m_commandList[ii].m_commandList->Close() );
}
}
void shutdown()
{
finish();
DX_RELEASE(m_fence, 0);
for (uint32_t ii = 0; ii < BX_COUNTOF(m_commandList); ++ii)
{
DX_RELEASE(m_commandList[ii].m_commandAllocator, 0);
DX_RELEASE(m_commandList[ii].m_commandList, 0);
}
DX_RELEASE(m_commandQueue, 0);
}
ID3D12GraphicsCommandList* alloc()
{
while (0 == m_control.reserve(1) )
{
CommandList& commandList = m_commandList[m_control.m_read];
WaitForSingleObject(commandList.m_event, INFINITE);
CloseHandle(commandList.m_event);
m_control.consume(1);
}
CommandList& commandList = m_commandList[m_control.m_current];
DX_CHECK(commandList.m_commandList->Reset(commandList.m_commandAllocator, NULL) );
return commandList.m_commandList;
}
uint64_t kick()
{
CommandList& commandList = m_commandList[m_control.m_current];
DX_CHECK(commandList.m_commandList->Close() );
ID3D12CommandList* commandLists[] = { commandList.m_commandList };
m_commandQueue->ExecuteCommandLists(BX_COUNTOF(commandLists), commandLists);
commandList.m_event = CreateEventExA(NULL, NULL, 0, EVENT_ALL_ACCESS);
const uint64_t fence = m_currentFence++;
m_commandQueue->Signal(m_fence, fence);
m_fence->SetEventOnCompletion(fence, commandList.m_event);
m_control.commit(1);
return fence;
}
void finish(uint64_t _waitFence = UINT64_MAX)
{
while (0 < m_control.available() )
{
CommandList& commandList = m_commandList[m_control.m_read];
WaitForSingleObject(commandList.m_event, INFINITE);
CloseHandle(commandList.m_event);
commandList.m_event = NULL;
m_completedFence = m_fence->GetCompletedValue();
m_commandQueue->Wait(m_fence, m_completedFence);
m_control.consume(1);
if (_waitFence <= m_completedFence)
{
return;
}
}
BX_CHECK(0 == m_control.available(), "");
}
struct CommandList
{
ID3D12GraphicsCommandList* m_commandList;
ID3D12CommandAllocator* m_commandAllocator;
HANDLE m_event;
};
ID3D12CommandQueue* m_commandQueue;
uint64_t m_currentFence;
uint64_t m_completedFence;
ID3D12Fence* m_fence;
CommandList m_commandList[4];
bx::RingBufferControl m_control;
};
} /* namespace d3d12 */ } // namespace bgfx
#endif // BGFX_RENDERER_D3D12_H_HEADER_GUARD

748
src/shader_dx9bc.cpp Normal file
View file

@ -0,0 +1,748 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#include "bgfx_p.h"
#include "shader_dx9bc.h"
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter");
BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunneeded-internal-declaration");
namespace bgfx
{
struct Dx9bcOpcodeInfo
{
uint8_t numOperands;
uint8_t numValues;
};
static const Dx9bcOpcodeInfo s_dx9bcOpcodeInfo[] =
{
{ 0, 0 }, // NOP
{ 2, 0 }, // MOV
{ 3, 0 }, // ADD
{ 1, 0 }, // SUB
{ 4, 0 }, // MAD
{ 3, 0 }, // MUL
{ 2, 0 }, // RCP
{ 2, 0 }, // RSQ
{ 3, 0 }, // DP3
{ 3, 0 }, // DP4
{ 3, 0 }, // MIN
{ 3, 0 }, // MAX
{ 3, 0 }, // SLT
{ 3, 0 }, // SGE
{ 2, 0 }, // EXP
{ 2, 0 }, // LOG
{ 1, 0 }, // LIT
{ 1, 0 }, // DST
{ 4, 0 }, // LRP
{ 2, 0 }, // FRC
{ 1, 0 }, // M4X4
{ 1, 0 }, // M4X3
{ 1, 0 }, // M3X4
{ 1, 0 }, // M3X3
{ 1, 0 }, // M3X2
{ 0, 0 }, // CALL
{ 0, 0 }, // CALLNZ
{ 0, 0 }, // LOOP
{ 0, 0 }, // RET
{ 0, 0 }, // ENDLOOP
{ 0, 0 }, // LABEL
{ 1, 1 }, // DCL
{ 3, 0 }, // POW
{ 1, 0 }, // CRS
{ 1, 0 }, // SGN
{ 1, 0 }, // ABS
{ 2, 0 }, // NRM
{ 4, 0 }, // SINCOS
{ 1, 0 }, // REP
{ 0, 0 }, // ENDREP
{ 1, 0 }, // IF
{ 2, 0 }, // IFC
{ 0, 0 }, // ELSE
{ 0, 0 }, // ENDIF
{ 0, 0 }, // BREAK
{ 2, 0 }, // BREAKC
{ 2, 0 }, // MOVA
{ 1, 4 }, // DEFB
{ 1, 4 }, // DEFI
{ 0, 0 }, // 0
{ 0, 0 }, // 1
{ 0, 0 }, // 2
{ 0, 0 }, // 3
{ 0, 0 }, // 4
{ 0, 0 }, // 5
{ 0, 0 }, // 6
{ 0, 0 }, // 7
{ 0, 0 }, // 8
{ 0, 0 }, // 9
{ 0, 0 }, // 10
{ 0, 0 }, // 11
{ 0, 0 }, // 12
{ 0, 0 }, // 13
{ 0, 0 }, // 14
{ 1, 0 }, // TEXCOORD
{ 1, 0 }, // TEXKILL
{ 3, 0 }, // TEX
{ 1, 0 }, // TEXBEM
{ 1, 0 }, // TEXBEM1
{ 1, 0 }, // TEXREG2AR
{ 1, 0 }, // TEXREG2GB
{ 1, 0 }, // TEXM3X2PAD
{ 1, 0 }, // TEXM3X2TEX
{ 1, 0 }, // TEXM3X3PAD
{ 1, 0 }, // TEXM3X3TEX
{ 1, 0 }, // TEXM3X3DIFF
{ 1, 0 }, // TEXM3X3SPEC
{ 1, 0 }, // TEXM3X3VSPEC
{ 2, 0 }, // EXPP
{ 2, 0 }, // LOGP
{ 4, 0 }, // CND
{ 1, 4 }, // DEF
{ 1, 0 }, // TEXREG2RGB
{ 1, 0 }, // TEXDP3TEX
{ 1, 0 }, // TEXM3X2DEPTH
{ 1, 0 }, // TEXDP3
{ 1, 0 }, // TEXM3X3
{ 1, 0 }, // TEXDEPTH
{ 4, 0 }, // CMP
{ 1, 0 }, // BEM
{ 4, 0 }, // DP2ADD
{ 2, 0 }, // DSX
{ 2, 0 }, // DSY
{ 5, 0 }, // TEXLDD
{ 1, 0 }, // SETP
{ 3, 0 }, // TEXLDL
{ 0, 0 }, // BREAKP
};
BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcodeInfo) == Dx9bcOpcode::Count);
static const char* s_dx9bcOpcode[] =
{
"nop",
"mov",
"add",
"sub",
"mad",
"mul",
"rcp",
"rsq",
"dp3",
"dp4",
"min",
"max",
"slt",
"sge",
"exp",
"log",
"lit",
"dst",
"lrp",
"frc",
"m4x4",
"m4x3",
"m3x4",
"m3x3",
"m3x2",
"call",
"callnz",
"loop",
"ret",
"endloop",
"label",
"dcl",
"pow",
"crs",
"sgn",
"abs",
"nrm",
"sincos",
"rep",
"endrep",
"if",
"ifc",
"else",
"endif",
"break",
"breakc",
"mova",
"defb",
"defi",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"texcoord",
"texkill",
"tex",
"texbem",
"texbem1",
"texreg2ar",
"texreg2gb",
"texm3x2pad",
"texm3x2tex",
"texm3x3pad",
"texm3x3tex",
"texm3x3diff",
"texm3x3spec",
"texm3x3vspec",
"expp",
"logp",
"cnd",
"def",
"texreg2rgb",
"texdp3tex",
"texm3x2depth",
"texdp3",
"texm3x3",
"texdepth",
"cmp",
"bem",
"dp2add",
"dsx",
"dsy",
"texldd",
"setp",
"texldl",
"breakp",
};
BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcode) == Dx9bcOpcode::Count);
const char* getName(Dx9bcOpcode::Enum _opcode)
{
BX_CHECK(_opcode < Dx9bcOpcode::Count, "Unknown opcode id %d (%x).", _opcode, _opcode);
return s_dx9bcOpcode[_opcode];
}
static const char* s_dx9bcOperandType[] =
{
"r", // Temporary Register File
"v", // Input Register File
"c", // Constant Register File
"t", // Texture Register File (PS)
"oPos", // Rasterizer Register File
"oD", // Attribute Output Register File
"oT", // Texture Coordinate Output Register File
"output", // Output register file for VS3.0+
"i", // Constant Integer Vector Register File
"oColor", // Color Output Register File
"oDepth", // Depth Output Register File
"s", // Sampler State Register File
"c", // Constant Register File 2048 - 4095
"c", // Constant Register File 4096 - 6143
"c", // Constant Register File 6144 - 8191
"b", // Constant Boolean register file
"aL", // Loop counter register file
"tempfloat16", // 16-bit float temp register file
"misctype", // Miscellaneous (single) registers.
"label", // Label
"p", // Predicate register
};
BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOperandType) == Dx9bcOperandType::Count);
static const char* s_dx9bcDeclUsage[] =
{
"position",
"blendweight",
"blendindices",
"normal",
"psize",
"texcoord",
"tangent",
"binormal",
"tessfactor",
"positiont",
"color",
"fog",
"depth",
"sample",
};
BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcDeclUsage) == Dx9bcDeclUsage::Count);
int32_t read(bx::ReaderI* _reader, Dx9bcSubOperand& _subOperand)
{
int32_t size = 0;
uint32_t token;
size += bx::read(_reader, token);
_subOperand.type = Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
| ( (token & UINT32_C(0x00001800) ) >> 8) );
_subOperand.regIndex = (token & UINT32_C(0x000007ff) );
_subOperand.swizzleBits = ( (token & UINT32_C(0x00ff0000) ) >> 16);
return size;
}
int32_t write(bx::WriterI* _writer, const Dx9bcSubOperand& _subOperand)
{
int32_t size = 0;
uint32_t token = 0;
token |= (_subOperand.type << 28) & UINT32_C(0x70000000);
token |= (_subOperand.type << 8) & UINT32_C(0x00001800);
token |= _subOperand.regIndex & UINT32_C(0x000007ff);
token |= (_subOperand.swizzleBits << 16) & UINT32_C(0x00ff0000);
size += bx::write(_writer, token);
return size;
}
int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand)
{
int32_t size = 0;
uint32_t token;
size += bx::read(_reader, token);
_operand.type = Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
| ( (token & UINT32_C(0x00001800) ) >> 8) );
_operand.regIndex = (token & UINT32_C(0x000007ff) );
_operand.addrMode = Dx9bcOperandAddrMode::Enum( (token & UINT32_C(0x00002000) ) >> 13);
if (_operand.destination)
{
// Destination Parameter Token
// https://msdn.microsoft.com/en-us/library/ff552738.aspx
_operand.writeMask = ( (token & UINT32_C(0x000f0000) ) >> 16);
_operand.saturate = 0 != (token & UINT32_C(0x00100000) );
_operand.partialPrecision = 0 != (token & UINT32_C(0x00200000) );
_operand.centroid = 0 != (token & UINT32_C(0x00400000) );
}
else
{
// Source Parameter Token
// https://msdn.microsoft.com/en-us/library/ff569716%28v=vs.85%29.aspx
_operand.writeMask = 0;
_operand.saturate = false;
_operand.partialPrecision = false;
_operand.centroid = false;
_operand.swizzleBits = ( (token & UINT32_C(0x00ff0000) ) >> 16);
}
if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
{
size += read(_reader, _operand.subOperand);
}
return size;
}
int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand)
{
int32_t size = 0;
uint32_t token = 0;
token |= (_operand.type << 28) & UINT32_C(0x70000000);
token |= (_operand.type << 8) & UINT32_C(0x00001800);
token |= _operand.regIndex & UINT32_C(0x000007ff);
token |= (_operand.addrMode << 13) & UINT32_C(0x00002000);
size += bx::write(_writer, token);
if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
{
size += write(_writer, _operand.subOperand);
}
return size;
}
int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction)
{
int32_t size = 0;
uint32_t token;
size += bx::read(_reader, token);
_instruction.opcode = Dx9bcOpcode::Enum( (token & UINT32_C(0x0000ffff) ) );
if (Dx9bcOpcode::Comment == _instruction.opcode)
{
_instruction.specific = 0;
_instruction.length = uint16_t( (token & UINT32_C(0x7fff0000) ) >> 16) + 1;
_instruction.predicated = false;
_instruction.coissue = false;
}
else
{
_instruction.specific = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16);
_instruction.length = uint8_t( (token & UINT32_C(0x0f000000) ) >> 24) + 1;
_instruction.predicated = 0 != (token & UINT32_C(0x10000000) );
_instruction.coissue = 0 != (token & UINT32_C(0x40000000) );
}
if (Dx9bcOpcode::Count <= _instruction.opcode)
{
if (Dx9bcOpcode::Comment == _instruction.opcode)
{
for (int32_t ii = 0, num = _instruction.length-1; ii < num; ++ii)
{
uint32_t tmp;
size += bx::read(_reader, tmp);
}
}
return size;
}
uint32_t currOp = 0;
const Dx9bcOpcodeInfo& info = s_dx9bcOpcodeInfo[bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count)];
_instruction.numOperands = info.numOperands;
_instruction.numValues = info.numValues;
switch (_instruction.opcode)
{
case Dx9bcOpcode::SINCOS:
if (5 > _instruction.length)
{
_instruction.numOperands = 2;
}
break;
default:
break;
};
//BX_TRACE("%d (%d), %d, %d, 0x%08x"
// , _instruction.opcode
// , bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count)
// , _instruction.length
// , _instruction.numOperands
// , token
// );
const bool valuesBeforeOpcode = false
|| Dx9bcOpcode::DCL == _instruction.opcode
;
if (valuesBeforeOpcode
&& 0 < info.numValues)
{
size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) );
}
_instruction.operand[0].destination = true;
switch (_instruction.numOperands)
{
case 6: size += read(_reader, _instruction.operand[currOp++]);
case 5: size += read(_reader, _instruction.operand[currOp++]);
case 4: size += read(_reader, _instruction.operand[currOp++]);
case 3: size += read(_reader, _instruction.operand[currOp++]);
case 2: size += read(_reader, _instruction.operand[currOp++]);
case 1: size += read(_reader, _instruction.operand[currOp++]);
case 0:
if (!valuesBeforeOpcode
&& 0 < info.numValues)
{
size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) );
}
break;
default:
BX_CHECK(false, "Instruction %s with invalid number of operands %d (numValues %d)."
, getName(_instruction.opcode)
, _instruction.numOperands
, info.numValues
);
break;
}
return size;
}
int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction)
{
int32_t size = 0;
uint32_t token = 0;
token |= _instruction.opcode & UINT32_C(0x0000ffff);
token |= (_instruction.specific << 16) & UINT32_C(0x00ff0000);
token |= ( (_instruction.length - 1) << 24) & UINT32_C(0x0f000000);
size += bx::write(_writer, token);
uint32_t currOp = 0;
switch (_instruction.numOperands)
{
case 6: size += write(_writer, _instruction.operand[currOp++]);
case 5: size += write(_writer, _instruction.operand[currOp++]);
case 4: size += write(_writer, _instruction.operand[currOp++]);
case 3: size += write(_writer, _instruction.operand[currOp++]);
case 2: size += write(_writer, _instruction.operand[currOp++]);
case 1: size += write(_writer, _instruction.operand[currOp++]);
case 0:
break;
}
return 0;
}
int32_t toString(char* _out, int32_t _size, const Dx9bcInstruction& _instruction)
{
int32_t size = 0;
if (Dx9bcOpcode::Comment == _instruction.opcode
|| Dx9bcOpcode::Phase == _instruction.opcode)
{
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "// %x"
, _instruction.opcode
);
return size;
}
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%2d %s"
, _instruction.opcode
, getName(_instruction.opcode)
);
switch (_instruction.opcode)
{
case Dx9bcOpcode::DCL:
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "_%s%d (%d, %d, %d, %d)"
, s_dx9bcDeclUsage[_instruction.value[0] & UINT32_C(0x0000000f)]
, (_instruction.value[0] & UINT32_C(0x000f0000) )>>16
, (_instruction.value[0] & UINT32_C(0x08000000) )>>27 // ?
, (_instruction.value[0] & UINT32_C(0x10000000) )>>28 // texture2d
, (_instruction.value[0] & UINT32_C(0x20000000) )>>29 // textureCube
, (_instruction.value[0] & UINT32_C(0x40000000) )>>30 // texture3d
);
break;
default:
break;
}
for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii)
{
const Dx9bcOperand& operand = _instruction.operand[ii];
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s%s%d"
, 0 == ii ? " " : ", "
, s_dx9bcOperandType[operand.type]
, operand.regIndex
);
if (operand.destination)
{
if (0xf > operand.writeMask
&& 0 < operand.writeMask)
{
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, ".%s%s%s%s"
, 0 == (operand.writeMask & 1) ? "" : "x"
, 0 == (operand.writeMask & 2) ? "" : "y"
, 0 == (operand.writeMask & 4) ? "" : "z"
, 0 == (operand.writeMask & 8) ? "" : "w"
);
}
}
else
{
if (Dx9bcOperandAddrMode::Relative == operand.addrMode)
{
const bool array = true;
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "["
);
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s%d"
, s_dx9bcOperandType[operand.subOperand.type]
, operand.subOperand.regIndex
);
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s"
, array ? "]" : ""
);
}
if (0xe4 != operand.swizzleBits)
{
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, ".%c%c%c%c"
, "xyzw"[(operand.swizzleBits )&0x3]
, "xyzw"[(operand.swizzleBits>>2)&0x3]
, "xyzw"[(operand.swizzleBits>>4)&0x3]
, "xyzw"[(operand.swizzleBits>>6)&0x3]
);
}
}
}
switch (_instruction.opcode)
{
case Dx9bcOpcode::DEF:
for (uint32_t jj = 0; jj < _instruction.numValues; ++jj)
{
union { int32_t i; float f; } cast = { _instruction.value[jj] };
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s%f%s"
, 0 == jj ? " (" : ", "
, cast.f
, uint32_t(_instruction.numValues-1) == jj ? ")" : ""
);
}
break;
case Dx9bcOpcode::DEFI:
for (uint32_t jj = 0; jj < _instruction.numValues; ++jj)
{
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s%d%s"
, 0 == jj ? " (" : ", "
, _instruction.value[jj]
, uint32_t(_instruction.numValues-1) == jj ? ")" : ""
);
}
break;
default:
break;
}
return size;
}
int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader)
{
int32_t size = 0;
int64_t offset = bx::seek(_reader);
for (;;)
{
Dx9bcInstruction instruction;
int32_t length = read(_reader, instruction);
size += length;
if (Dx9bcOpcode::Count > instruction.opcode)
{
char temp[512];
toString(temp, 512, instruction);
BX_CHECK(length/4 == instruction.length
, "%s\nread %d, expected %d"
, temp
, length/4
, instruction.length
);
}
else
{
if (Dx9bcOpcode::End == instruction.opcode)
{
size -= length;
break;
}
}
}
bx::seek(_reader, offset, bx::Whence::Begin);
_shader.byteCode.resize(size);
bx::read(_reader, _shader.byteCode.data(), size);
return size;
}
int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader)
{
BX_UNUSED(_writer, _shader);
return 0;
}
int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc)
{
int32_t size = 0;
size += bx::read(_reader, _bc.version);
bool pixelShader = (0xffff0000 == (_bc.version & 0xffff0000) );
uint32_t versionMajor = (_bc.version>>8)&0xff;
uint32_t versionMinor = _bc.version&0xff;
BX_TRACE("%s shader %d.%d"
, pixelShader ? "pixel" : "vertex"
, versionMajor
, versionMinor
);
size += read(_reader, _bc.shader);
return size;
}
int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc)
{
BX_UNUSED(_writer, _dxbc);
return 0;
}
void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData)
{
bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
//BX_TRACE("parse %d", _src.byteCode.size());
for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
{
Dx9bcInstruction instruction;
uint32_t size = read(&reader, instruction);
BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length);
_fn(token * sizeof(uint32_t), instruction, _userData);
token += instruction.length;
}
}
void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData)
{
bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
bx::CrtAllocator r;
bx::MemoryBlock mb(&r);
bx::MemoryWriter writer(&mb);
for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
{
Dx9bcInstruction instruction;
uint32_t size = read(&reader, instruction);
BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length);
_fn(instruction, _userData);
write(&writer, instruction);
token += instruction.length;
}
uint8_t* data = (uint8_t*)mb.more();
uint32_t size = uint32_t(bx::getSize(&writer) );
_dst.byteCode.reserve(size);
memcpy(_dst.byteCode.data(), data, size);
}
} // namespace bgfx

258
src/shader_dx9bc.h Normal file
View file

@ -0,0 +1,258 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#ifndef BGFX_SHADER_DX9BC_H
#define BGFX_SHADER_DX9BC_H
#include <bx/readerwriter.h>
namespace bgfx
{
struct Dx9bcOpcode
{
enum Enum
{
NOP,
MOV,
ADD,
SUB,
MAD,
MUL,
RCP,
RSQ,
DP3,
DP4,
MIN,
MAX,
SLT,
SGE,
EXP,
LOG,
LIT,
DST,
LRP,
FRC,
M4X4,
M4X3,
M3X4,
M3X3,
M3X2,
CALL,
CALLNZ,
LOOP,
RET,
ENDLOOP,
LABEL,
DCL,
POW,
CRS,
SGN,
ABS,
NRM,
SINCOS,
REP,
ENDREP,
IF,
IFC,
ELSE,
ENDIF,
BREAK,
BREAKC,
MOVA,
DEFB,
DEFI,
Unknown = 63,
TEXCOORD,
TEXKILL,
TEX,
TEXBEM,
TEXBEM1,
TEXREG2AR,
TEXREG2GB,
TEXM3X2PAD,
TEXM3X2TEX,
TEXM3X3PAD,
TEXM3X3TEX,
TEXM3X3DIFF,
TEXM3X3SPEC,
TEXM3X3VSPEC,
EXPP,
LOGP,
CND,
DEF,
TEXREG2RGB,
TEXDP3TEX,
TEXM3X2DEPTH,
TEXDP3,
TEXM3X3,
TEXDEPTH,
CMP,
BEM,
DP2ADD,
DSX,
DSY,
TEXLDD,
SETP,
TEXLDL,
BREAKP,
Count,
Phase = 0xfffd,
Comment = 0xfffe,
End = 0xffff
};
};
const char* getName(Dx9bcOpcode::Enum _opcode);
struct Dx9bcResourceDim
{
enum Enum
{
Unknown,
Texture1D,
Texture2D,
TextureCube,
Texture3D,
};
};
struct Dx9bcOperandType
{
enum Enum
{
Temp,
Input,
Const,
Texture,
RastOut,
AttrOut,
TexCrdOut,
Output,
ConstInt,
ColorOut,
DepthOut,
Sampler,
Const2,
Const3,
Const4,
ConstBool,
Loop,
TempFloat16,
MiscType,
Label,
Predicate,
Count
};
};
struct Dx9bcDeclUsage
{
enum Enum
{
Position,
BlendWeight,
BlendIndices,
Normal,
Psize,
Texcoord,
Tangent,
Binormal,
TessFactor,
PositionT,
Color,
Fog,
Depth,
Sample,
Count
};
};
struct Dx9bcOperandAddrMode
{
enum Enum
{
Absolute,
Relative,
Count
};
};
struct Dx9bcSubOperand
{
Dx9bcOperandType::Enum type;
uint32_t regIndex;
uint8_t swizzleBits;
};
struct Dx9bcOperand
{
Dx9bcOperandType::Enum type;
uint32_t regIndex;
bool destination;
// Destination
uint8_t writeMask;
bool saturate;
bool partialPrecision;
bool centroid;
// Source
uint8_t swizzleBits;
Dx9bcOperandAddrMode::Enum addrMode;
Dx9bcSubOperand subOperand;
};
struct Dx9bcInstruction
{
Dx9bcOpcode::Enum opcode;
uint16_t length;
uint8_t numOperands;
uint8_t numValues;
uint8_t specific;
bool predicated;
bool coissue;
Dx9bcOperand operand[6];
int32_t value[4];
};
int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction);
int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction);
int32_t toString(char* _out, int32_t _size, const Dx9bcInstruction& _instruction);
struct Dx9bcShader
{
stl::vector<uint8_t> byteCode;
};
int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader);
int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader);
struct Dx9bc
{
uint32_t version;
Dx9bcShader shader;
};
int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _dx9bc);
int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dx9bc);
typedef void (*Dx9bcParseFn)(uint32_t _offset, const Dx9bcInstruction& _instruction, void* _userData);
void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData);
typedef void (*Dx9bcFilterFn)(Dx9bcInstruction& _instruction, void* _userData);
void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData);
} // namespace bgfx
#endif // BGFX_SHADER_DX9BC_H

1851
src/shader_dxbc.cpp Normal file

File diff suppressed because it is too large Load diff

608
src/shader_dxbc.h Normal file
View file

@ -0,0 +1,608 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#ifndef BGFX_SHADER_DXBC_H
#define BGFX_SHADER_DXBC_H
#include <bx/readerwriter.h>
namespace bgfx
{
struct DxbcOpcode
{
enum Enum
{
ADD,
AND,
BREAK,
BREAKC,
CALL,
CALLC,
CASE,
CONTINUE,
CONTINUEC,
CUT,
DEFAULT,
DERIV_RTX,
DERIV_RTY,
DISCARD,
DIV,
DP2,
DP3,
DP4,
ELSE,
EMIT,
EMITTHENCUT,
ENDIF,
ENDLOOP,
ENDSWITCH,
EQ,
EXP,
FRC,
FTOI,
FTOU,
GE,
IADD,
IF,
IEQ,
IGE,
ILT,
IMAD,
IMAX,
IMIN,
IMUL,
INE,
INEG,
ISHL,
ISHR,
ITOF,
LABEL,
LD,
LD_MS,
LOG,
LOOP,
LT,
MAD,
MIN,
MAX,
CUSTOMDATA,
MOV,
MOVC,
MUL,
NE,
NOP,
NOT,
OR,
RESINFO,
RET,
RETC,
ROUND_NE,
ROUND_NI,
ROUND_PI,
ROUND_Z,
RSQ,
SAMPLE,
SAMPLE_C,
SAMPLE_C_LZ,
SAMPLE_L,
SAMPLE_D,
SAMPLE_B,
SQRT,
SWITCH,
SINCOS,
UDIV,
ULT,
UGE,
UMUL,
UMAD,
UMAX,
UMIN,
USHR,
UTOF,
XOR,
DCL_RESOURCE,
DCL_CONSTANT_BUFFER,
DCL_SAMPLER,
DCL_INDEX_RANGE,
DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY,
DCL_GS_INPUT_PRIMITIVE,
DCL_MAX_OUTPUT_VERTEX_COUNT,
DCL_INPUT,
DCL_INPUT_SGV,
DCL_INPUT_SIV,
DCL_INPUT_PS,
DCL_INPUT_PS_SGV,
DCL_INPUT_PS_SIV,
DCL_OUTPUT,
DCL_OUTPUT_SGV,
DCL_OUTPUT_SIV,
DCL_TEMPS,
DCL_INDEXABLE_TEMP,
DCL_GLOBAL_FLAGS,
UnknownD3D10,
LOD,
GATHER4,
SAMPLE_POS,
SAMPLE_INFO,
UnknownD3D10_1,
HS_DECLS,
HS_CONTROL_POINT_PHASE,
HS_FORK_PHASE,
HS_JOIN_PHASE,
EMIT_STREAM,
CUT_STREAM,
EMITTHENCUT_STREAM,
INTERFACE_CALL,
BUFINFO,
DERIV_RTX_COARSE,
DERIV_RTX_FINE,
DERIV_RTY_COARSE,
DERIV_RTY_FINE,
GATHER4_C,
GATHER4_PO,
GATHER4_PO_C,
RCP,
F32TOF16,
F16TOF32,
UADDC,
USUBB,
COUNTBITS,
FIRSTBIT_HI,
FIRSTBIT_LO,
FIRSTBIT_SHI,
UBFE,
IBFE,
BFI,
BFREV,
SWAPC,
DCL_STREAM,
DCL_FUNCTION_BODY,
DCL_FUNCTION_TABLE,
DCL_INTERFACE,
DCL_INPUT_CONTROL_POINT_COUNT,
DCL_OUTPUT_CONTROL_POINT_COUNT,
DCL_TESS_DOMAIN,
DCL_TESS_PARTITIONING,
DCL_TESS_OUTPUT_PRIMITIVE,
DCL_HS_MAX_TESSFACTOR,
DCL_HS_FORK_PHASE_INSTANCE_COUNT,
DCL_HS_JOIN_PHASE_INSTANCE_COUNT,
DCL_THREAD_GROUP,
DCL_UNORDERED_ACCESS_VIEW_TYPED,
DCL_UNORDERED_ACCESS_VIEW_RAW,
DCL_UNORDERED_ACCESS_VIEW_STRUCTURED,
DCL_THREAD_GROUP_SHARED_MEMORY_RAW,
DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED,
DCL_RESOURCE_RAW,
DCL_RESOURCE_STRUCTURED,
LD_UAV_TYPED,
STORE_UAV_TYPED,
LD_RAW,
STORE_RAW,
LD_STRUCTURED,
STORE_STRUCTURED,
ATOMIC_AND,
ATOMIC_OR,
ATOMIC_XOR,
ATOMIC_CMP_STORE,
ATOMIC_IADD,
ATOMIC_IMAX,
ATOMIC_IMIN,
ATOMIC_UMAX,
ATOMIC_UMIN,
IMM_ATOMIC_ALLOC,
IMM_ATOMIC_CONSUME,
IMM_ATOMIC_IADD,
IMM_ATOMIC_AND,
IMM_ATOMIC_OR,
IMM_ATOMIC_XOR,
IMM_ATOMIC_EXCH,
IMM_ATOMIC_CMP_EXCH,
IMM_ATOMIC_IMAX,
IMM_ATOMIC_IMIN,
IMM_ATOMIC_UMAX,
IMM_ATOMIC_UMIN,
SYNC,
DADD,
DMAX,
DMIN,
DMUL,
DEQ,
DGE,
DLT,
DNE,
DMOV,
DMOVC,
DTOF,
FTOD,
EVAL_SNAPPED,
EVAL_SAMPLE_INDEX,
EVAL_CENTROID,
DCL_GS_INSTANCE_COUNT,
ABORT,
DEBUG_BREAK,
UnknownD3D11,
DDIV,
DFMA,
DRCP,
MSAD,
DTOI,
DTOU,
ITOD,
UTOD,
Count
};
};
const char* getName(DxbcOpcode::Enum _opcode);
struct DxbcBuiltin
{
// D3D_NAME
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff728724%28v=vs.85%29.aspx
// mesa/src/gallium/state_trackers/d3d1x/d3d1xshader/defs/svs.txt
enum Enum
{
Undefined,
Position,
ClipDistance,
CullDistance,
RenderTargetArrayIndex,
ViewportArrayIndex,
VertexId,
PrimitiveId,
InstanceId,
IsFrontFace,
SampleIndex,
FinalQuadUEq0EdgeTessFactor,
FinalQuadVEq0EdgeTessFactor,
FinalQuadUEq1EdgeTessFactor,
FinalQuadVEq1EdgeTessFactor,
FinalQuadUInsideTessFactor,
FinalQuadVInsideTessFactor,
FinalTriUEq0EdgeTessFactor,
FinalTriVEq0EdgeTessFactor,
FinalTriWEq0EdgeTessFactor,
FinalTriInsideTessFactor,
FinalLineDetailTessFactor,
FinalLineDensityTessFactor,
Target = 64,
Depth,
Coverage,
DepthGreaterEqual,
DepthLessEqual,
StencilRef,
InnerCoverage,
};
};
struct DxbcResourceDim
{
// D3D_SRV_DIMENSION
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff728736%28v=vs.85%29.aspx
// mesa/src/gallium/state_trackers/d3d1x/d3d1xshader/defs/targets.txt
enum Enum
{
Unknown,
Buffer,
Texture1D,
Texture2D,
Texture2DMS,
Texture3D,
TextureCube,
Texture1DArray,
Texture2DArray,
Texture2DMSArray,
TextureCubearray,
RawBuffer,
StructuredBuffer,
Count
};
};
struct DxbcInterpolation
{
enum Enum
{
Unknown,
Constant,
Linear,
LinearCentroid,
LinearNoPerspective,
LinearNoPerspectiveCentroid,
LinearSample,
LinearNoPerspectiveSample,
Count
};
};
struct DxbcResourceReturnType
{
enum Enum
{
Unorm,
Snorm,
Sint,
Uint,
Float,
Mixed,
Double,
Continued,
Unused,
Count
};
};
struct DxbcComponentType
{
enum Enum
{
Unknown,
Uint32,
Int32,
Float,
Count
};
};
struct DxbcPrecision
{
enum Enum
{
Default,
Half,
Float2_8,
Reserved,
Int16,
Uint16,
Any16 = 0xf0,
Any10 = 0xf1,
};
};
struct DxbcOperandType
{
enum Enum
{
Temp,
Input,
Output,
TempArray,
Imm32,
Imm64,
Sampler,
Resource,
ConstantBuffer,
ImmConstantBuffer,
Label,
PrimitiveID,
OutputDepth,
Null,
Rasterizer,
CoverageMask,
Stream,
FunctionBody,
FunctionTable,
Interface,
FunctionInput,
FunctionOutput,
OutputControlPointId,
InputForkInstanceId,
InputJoinInstanceId,
InputControlPoint,
OutputControlPoint,
InputPatchConstant,
InputDomainPoint,
ThisPointer,
UnorderedAccessView,
ThreadGroupSharedMemory,
InputThreadId,
InputThreadGroupId,
InputThreadIdInGroup,
InputCoverageMask,
InputThreadIdInGroupFlattened,
InputGsInstanceId,
OutputDepthGreaterEqual,
OutputDepthLessEqual,
CycleCounter,
Count
};
};
struct DxbcOperandAddrMode
{
enum Enum
{
Imm32,
Imm64,
Reg,
RegImm32,
RegImm64,
Count
};
};
struct DxbcOperandMode
{
enum Enum
{
Mask,
Swizzle,
Scalar,
Count
};
};
struct DxbcSubOperand
{
DxbcOperandType::Enum type;
uint8_t mode;
uint8_t modeBits;
uint8_t num;
uint8_t numAddrModes;
uint8_t addrMode;
uint32_t regIndex;
};
struct DxbcOperand
{
DxbcOperandType::Enum type;
DxbcOperandMode::Enum mode;
uint8_t modeBits;
uint8_t num;
bool extended;
uint32_t extBits;
uint8_t numAddrModes;
uint8_t addrMode[3];
uint32_t regIndex[3];
DxbcSubOperand subOperand[3];
union
{
uint32_t imm32[4];
uint64_t imm64[4];
} un;
};
struct DxbcInstruction
{
struct ExtendedType
{
enum Enum
{
Empty,
SampleControls,
ResourceDim,
ResourceReturnType,
Count
};
};
DxbcOpcode::Enum opcode;
uint32_t value[3];
uint32_t length;
uint8_t numOperands;
ExtendedType::Enum extended[3];
//
DxbcResourceDim::Enum srv;
uint8_t samples;
//
DxbcInterpolation::Enum interpolation;
//
bool shadow;
bool mono;
//
bool allowRefactoring;
bool fp64;
bool earlyDepth;
bool enableBuffers;
bool skipOptimization;
bool enableMinPrecision;
bool enableDoubleExtensions;
bool enableShaderExtensions;
//
bool threadsInGroup;
bool sharedMemory;
bool uavGroup;
bool uavGlobal;
//
DxbcResourceReturnType::Enum retType;
bool saturate;
uint8_t testNZ;
//
uint8_t sampleOffsets[3];
uint8_t resourceTarget;
uint8_t resourceStride;
DxbcResourceReturnType::Enum resourceReturnTypes[4];
DxbcOperand operand[6];
};
int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction);
int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction);
int32_t toString(char* _out, int32_t _size, const DxbcInstruction& _instruction);
struct DxbcSignature
{
struct Element
{
stl::string name;
uint32_t semanticIndex;
DxbcBuiltin::Enum valueType;
DxbcComponentType::Enum componentType;
uint32_t registerIndex;
uint8_t mask;
uint8_t readWriteMask;
uint8_t stream;
};
uint32_t key;
stl::vector<Element> elements;
};
int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature);
int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature);
struct DxbcShader
{
uint32_t version;
stl::vector<uint8_t> byteCode;
};
int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader);
int32_t write(bx::WriterI* _writer, const DxbcShader& _shader);
typedef void (*DxbcParseFn)(uint32_t _offset, const DxbcInstruction& _instruction, void* _userData);
void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData);
typedef void (*DxbcFilterFn)(DxbcInstruction& _instruction, void* _userData);
void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData);
struct DxbcContext
{
struct Header
{
uint32_t magic;
uint8_t hash[16];
uint32_t version;
uint32_t size;
uint32_t numChunks;
};
Header header;
DxbcSignature inputSignature;
DxbcSignature outputSignature;
DxbcShader shader;
};
int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc);
int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc);
/// Calculate DXBC hash from data.
void dxbcHash(const void* _data, uint32_t _size, void* _digest);
} // namespace bgfx
#endif // BGFX_SHADER_DXBC_H

732
src/shader_spirv.cpp Normal file
View file

@ -0,0 +1,732 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#include "bgfx_p.h"
#include "shader_spirv.h"
namespace bgfx
{
struct SpirvOpcodeInfo
{
uint8_t numOperands;
uint8_t numValues;
bool hasVariable;
};
static const SpirvOpcodeInfo s_sprivOpcodeInfo[] =
{
{ 0, 0, false }, // Nop,
{ 0, 0, true }, // Source
{ 0, 0, true }, // SourceExtension
{ 0, 0, false }, // Extension
{ 0, 1, true }, // ExtInstImport
{ 0, 2, false }, // MemoryModel
{ 0, 2, false }, // EntryPoint
{ 0, 0, false }, // ExecutionMode
{ 0, 1, false }, // TypeVoid
{ 0, 1, false }, // TypeBool
{ 0, 3, false }, // TypeInt
{ 0, 2, false }, // TypeFloat
{ 0, 3, false }, // TypeVector
{ 0, 3, false }, // TypeMatrix
{ 1, 7, false }, // TypeSampler
{ 0, 0, false }, // TypeFilter
{ 0, 0, false }, // TypeArray
{ 0, 0, false }, // TypeRuntimeArray
{ 0, 0, false }, // TypeStruct
{ 0, 0, false }, // TypeOpaque
{ 0, 3, false }, // TypePointer
{ 0, 2, true }, // TypeFunction
{ 0, 0, false }, // TypeEvent
{ 0, 0, false }, // TypeDeviceEvent
{ 0, 0, false }, // TypeReserveId
{ 0, 0, false }, // TypeQueue
{ 0, 0, false }, // TypePipe
{ 0, 0, false }, // ConstantTrue
{ 0, 0, false }, // ConstantFalse
{ 0, 2, true }, // Constant
{ 0, 2, true }, // ConstantComposite
{ 0, 0, false }, // ConstantSampler
{ 0, 0, false }, // ConstantNullPointer
{ 0, 0, false }, // ConstantNullObject
{ 0, 0, false }, // SpecConstantTrue
{ 0, 0, false }, // SpecConstantFalse
{ 0, 0, false }, // SpecConstant
{ 0, 0, false }, // SpecConstantComposite
{ 0, 3, true }, // Variable
{ 0, 0, false }, // VariableArray
{ 0, 4, false }, // Function
{ 0, 0, false }, // FunctionParameter
{ 0, 0, false }, // FunctionEnd
{ 0, 0, false }, // FunctionCall
{ 0, 0, false }, // ExtInst
{ 0, 0, false }, // Undef
{ 0, 0, false }, // Load
{ 0, 2, true }, // Store
{ 0, 0, false }, // Phi
{ 0, 0, false }, // DecorationGroup
{ 0, 2, true }, // Decorate
{ 0, 0, false }, // MemberDecorate
{ 0, 0, false }, // GroupDecorate
{ 0, 0, false }, // GroupMemberDecorate
{ 0, 1, true }, // Name
{ 0, 1, true }, // MemberName
{ 0, 0, false }, // String
{ 0, 0, false }, // Line
{ 0, 0, false }, // VectorExtractDynamic
{ 0, 0, false }, // VectorInsertDynamic
{ 0, 0, false }, // VectorShuffle
{ 0, 0, false }, // CompositeConstruct
{ 0, 0, false }, // CompositeExtract
{ 0, 0, false }, // CompositeInsert
{ 0, 0, false }, // CopyObject
{ 0, 0, false }, // CopyMemory
{ 0, 0, false }, // CopyMemorySized
{ 0, 0, false }, // Sampler
{ 0, 0, false }, // TextureSample
{ 0, 0, false }, // TextureSampleDref
{ 0, 0, false }, // TextureSampleLod
{ 0, 0, false }, // TextureSampleProj
{ 0, 0, false }, // TextureSampleGrad
{ 0, 0, false }, // TextureSampleOffset
{ 0, 0, false }, // TextureSampleProjLod
{ 0, 0, false }, // TextureSampleProjGrad
{ 0, 0, false }, // TextureSampleLodOffset
{ 0, 0, false }, // TextureSampleProjOffset
{ 0, 0, false }, // TextureSampleGradOffset
{ 0, 0, false }, // TextureSampleProjLodOffset
{ 0, 0, false }, // TextureSampleProjGradOffset
{ 0, 0, false }, // TextureFetchTexelLod
{ 0, 0, false }, // TextureFetchTexelOffset
{ 0, 0, false }, // TextureFetchSample
{ 0, 0, false }, // TextureFetchTexel
{ 0, 0, false }, // TextureGather
{ 0, 0, false }, // TextureGatherOffset
{ 0, 0, false }, // TextureGatherOffsets
{ 0, 0, false }, // TextureQuerySizeLod
{ 0, 0, false }, // TextureQuerySize
{ 0, 0, false }, // TextureQueryLod
{ 0, 0, false }, // TextureQueryLevels
{ 0, 0, false }, // TextureQuerySamples
{ 0, 0, false }, // AccessChain
{ 0, 0, false }, // InBoundsAccessChain
{ 0, 0, false }, // SNegate
{ 0, 0, false }, // FNegate
{ 0, 0, false }, // Not
{ 0, 0, false }, // Any
{ 0, 0, false }, // All
{ 0, 0, false }, // ConvertFToU
{ 0, 0, false }, // ConvertFToS
{ 0, 0, false }, // ConvertSToF
{ 0, 0, false }, // ConvertUToF
{ 0, 0, false }, // UConvert
{ 0, 0, false }, // SConvert
{ 0, 0, false }, // FConvert
{ 0, 0, false }, // ConvertPtrToU
{ 0, 0, false }, // ConvertUToPtr
{ 0, 0, false }, // PtrCastToGeneric
{ 0, 0, false }, // GenericCastToPtr
{ 0, 0, false }, // Bitcast
{ 0, 0, false }, // Transpose
{ 0, 0, false }, // IsNan
{ 0, 0, false }, // IsInf
{ 0, 0, false }, // IsFinite
{ 0, 0, false }, // IsNormal
{ 0, 0, false }, // SignBitSet
{ 0, 0, false }, // LessOrGreater
{ 0, 0, false }, // Ordered
{ 0, 0, false }, // Unordered
{ 0, 0, false }, // ArrayLength
{ 0, 0, false }, // IAdd
{ 0, 0, false }, // FAdd
{ 0, 0, false }, // ISub
{ 0, 0, false }, // FSub
{ 0, 0, false }, // IMul
{ 0, 0, false }, // FMul
{ 0, 0, false }, // UDiv
{ 0, 0, false }, // SDiv
{ 0, 0, false }, // FDiv
{ 0, 0, false }, // UMod
{ 0, 0, false }, // SRem
{ 0, 0, false }, // SMod
{ 0, 0, false }, // FRem
{ 0, 0, false }, // FMod
{ 0, 0, false }, // VectorTimesScalar
{ 0, 0, false }, // MatrixTimesScalar
{ 0, 0, false }, // VectorTimesMatrix
{ 0, 0, false }, // MatrixTimesVector
{ 0, 0, false }, // MatrixTimesMatrix
{ 0, 0, false }, // OuterProduct
{ 0, 0, false }, // Dot
{ 0, 0, false }, // ShiftRightLogical
{ 0, 0, false }, // ShiftRightArithmetic
{ 0, 0, false }, // ShiftLeftLogical
{ 0, 0, false }, // LogicalOr
{ 0, 0, false }, // LogicalXor
{ 0, 0, false }, // LogicalAnd
{ 0, 0, false }, // BitwiseOr
{ 0, 0, false }, // BitwiseXor
{ 0, 0, false }, // BitwiseAnd
{ 0, 0, false }, // Select
{ 0, 0, false }, // IEqual
{ 0, 0, false }, // FOrdEqual
{ 0, 0, false }, // FUnordEqual
{ 0, 0, false }, // INotEqual
{ 0, 0, false }, // FOrdNotEqual
{ 0, 0, false }, // FUnordNotEqual
{ 0, 0, false }, // ULessThan
{ 0, 0, false }, // SLessThan
{ 0, 0, false }, // FOrdLessThan
{ 0, 0, false }, // FUnordLessThan
{ 0, 0, false }, // UGreaterThan
{ 0, 0, false }, // SGreaterThan
{ 0, 0, false }, // FOrdGreaterThan
{ 0, 0, false }, // FUnordGreaterThan
{ 0, 0, false }, // ULessThanEqual
{ 0, 0, false }, // SLessThanEqual
{ 0, 0, false }, // FOrdLessThanEqual
{ 0, 0, false }, // FUnordLessThanEqual
{ 0, 0, false }, // UGreaterThanEqual
{ 0, 0, false }, // SGreaterThanEqual
{ 0, 0, false }, // FOrdGreaterThanEqual
{ 0, 0, false }, // FUnordGreaterThanEqual
{ 0, 0, false }, // DPdx
{ 0, 0, false }, // DPdy
{ 0, 0, false }, // Fwidth
{ 0, 0, false }, // DPdxFine
{ 0, 0, false }, // DPdyFine
{ 0, 0, false }, // FwidthFine
{ 0, 0, false }, // DPdxCoarse
{ 0, 0, false }, // DPdyCoarse
{ 0, 0, false }, // FwidthCoarse
{ 0, 0, false }, // EmitVertex
{ 0, 0, false }, // EndPrimitive
{ 0, 0, false }, // EmitStreamVertex
{ 0, 0, false }, // EndStreamPrimitive
{ 0, 0, false }, // ControlBarrier
{ 0, 0, false }, // MemoryBarrier
{ 0, 0, false }, // ImagePointer
{ 0, 0, false }, // AtomicInit
{ 0, 0, false }, // AtomicLoad
{ 0, 0, false }, // AtomicStore
{ 0, 0, false }, // AtomicExchange
{ 0, 0, false }, // AtomicCompareExchange
{ 0, 0, false }, // AtomicCompareExchangeWeak
{ 0, 0, false }, // AtomicIIncrement
{ 0, 0, false }, // AtomicIDecrement
{ 0, 0, false }, // AtomicIAdd
{ 0, 0, false }, // AtomicISub
{ 0, 0, false }, // AtomicUMin
{ 0, 0, false }, // AtomicUMax
{ 0, 0, false }, // AtomicAnd
{ 0, 0, false }, // AtomicOr
{ 0, 0, false }, // AtomicXor
{ 0, 0, false }, // LoopMerge
{ 0, 0, false }, // SelectionMerge
{ 0, 1, false }, // Label
{ 0, 1, false }, // Branch
{ 0, 0, false }, // BranchConditional
{ 0, 0, false }, // Switch
{ 0, 0, false }, // Kill
{ 0, 0, false }, // Return
{ 0, 0, false }, // ReturnValue
{ 0, 0, false }, // Unreachable
{ 0, 0, false }, // LifetimeStart
{ 0, 0, false }, // LifetimeStop
{ 0, 0, false }, // CompileFlag
{ 0, 0, false }, // AsyncGroupCopy
{ 0, 0, false }, // WaitGroupEvents
{ 0, 0, false }, // GroupAll
{ 0, 0, false }, // GroupAny
{ 0, 0, false }, // GroupBroadcast
{ 0, 0, false }, // GroupIAdd
{ 0, 0, false }, // GroupFAdd
{ 0, 0, false }, // GroupFMin
{ 0, 0, false }, // GroupUMin
{ 0, 0, false }, // GroupSMin
{ 0, 0, false }, // GroupFMax
{ 0, 0, false }, // GroupUMax
{ 0, 0, false }, // GroupSMax
{ 0, 0, false }, // GenericCastToPtrExplicit
{ 0, 0, false }, // GenericPtrMemSemantics
{ 0, 0, false }, // ReadPipe
{ 0, 0, false }, // WritePipe
{ 0, 0, false }, // ReservedReadPipe
{ 0, 0, false }, // ReservedWritePipe
{ 0, 0, false }, // ReserveReadPipePackets
{ 0, 0, false }, // ReserveWritePipePackets
{ 0, 0, false }, // CommitReadPipe
{ 0, 0, false }, // CommitWritePipe
{ 0, 0, false }, // IsValidReserveId
{ 0, 0, false }, // GetNumPipePackets
{ 0, 0, false }, // GetMaxPipePackets
{ 0, 0, false }, // GroupReserveReadPipePackets
{ 0, 0, false }, // GroupReserveWritePipePackets
{ 0, 0, false }, // GroupCommitReadPipe
{ 0, 0, false }, // GroupCommitWritePipe
{ 0, 0, false }, // EnqueueMarker
{ 0, 0, false }, // EnqueueKernel
{ 0, 0, false }, // GetKernelNDrangeSubGroupCount
{ 0, 0, false }, // GetKernelNDrangeMaxSubGroupSize
{ 0, 0, false }, // GetKernelWorkGroupSize
{ 0, 0, false }, // GetKernelPreferredWorkGroupSizeMultiple
{ 0, 0, false }, // RetainEvent
{ 0, 0, false }, // ReleaseEvent
{ 0, 0, false }, // CreateUserEvent
{ 0, 0, false }, // IsValidEvent
{ 0, 0, false }, // SetUserEventStatus
{ 0, 0, false }, // CaptureEventProfilingInfo
{ 0, 0, false }, // GetDefaultQueue
{ 0, 0, false }, // BuildNDRange
{ 0, 0, false }, // SatConvertSToU
{ 0, 0, false }, // SatConvertUToS
{ 0, 0, false }, // AtomicIMin
{ 0, 0, false }, // AtomicIMax
};
BX_STATIC_ASSERT(BX_COUNTOF(s_sprivOpcodeInfo) == SpirvOpcode::Count);
const char* s_spirvOpcode[] =
{
"Nop",
"Source",
"SourceExtension",
"Extension",
"ExtInstImport",
"MemoryModel",
"EntryPoint",
"ExecutionMode",
"TypeVoid",
"TypeBool",
"TypeInt",
"TypeFloat",
"TypeVector",
"TypeMatrix",
"TypeSampler",
"TypeFilter",
"TypeArray",
"TypeRuntimeArray",
"TypeStruct",
"TypeOpaque",
"TypePointer",
"TypeFunction",
"TypeEvent",
"TypeDeviceEvent",
"TypeReserveId",
"TypeQueue",
"TypePipe",
"ConstantTrue",
"ConstantFalse",
"Constant",
"ConstantComposite",
"ConstantSampler",
"ConstantNullPointer",
"ConstantNullObject",
"SpecConstantTrue",
"SpecConstantFalse",
"SpecConstant",
"SpecConstantComposite",
"Variable",
"VariableArray",
"Function",
"FunctionParameter",
"FunctionEnd",
"FunctionCall",
"ExtInst",
"Undef",
"Load",
"Store",
"Phi",
"DecorationGroup",
"Decorate",
"MemberDecorate",
"GroupDecorate",
"GroupMemberDecorate",
"Name",
"MemberName",
"String",
"Line",
"VectorExtractDynamic",
"VectorInsertDynamic",
"VectorShuffle",
"CompositeConstruct",
"CompositeExtract",
"CompositeInsert",
"CopyObject",
"CopyMemory",
"CopyMemorySized",
"Sampler",
"TextureSample",
"TextureSampleDref",
"TextureSampleLod",
"TextureSampleProj",
"TextureSampleGrad",
"TextureSampleOffset",
"TextureSampleProjLod",
"TextureSampleProjGrad",
"TextureSampleLodOffset",
"TextureSampleProjOffset",
"TextureSampleGradOffset",
"TextureSampleProjLodOffset",
"TextureSampleProjGradOffset",
"TextureFetchTexelLod",
"TextureFetchTexelOffset",
"TextureFetchSample",
"TextureFetchTexel",
"TextureGather",
"TextureGatherOffset",
"TextureGatherOffsets",
"TextureQuerySizeLod",
"TextureQuerySize",
"TextureQueryLod",
"TextureQueryLevels",
"TextureQuerySamples",
"AccessChain",
"InBoundsAccessChain",
"SNegate",
"FNegate",
"Not",
"Any",
"All",
"ConvertFToU",
"ConvertFToS",
"ConvertSToF",
"ConvertUToF",
"UConvert",
"SConvert",
"FConvert",
"ConvertPtrToU",
"ConvertUToPtr",
"PtrCastToGeneric",
"GenericCastToPtr",
"Bitcast",
"Transpose",
"IsNan",
"IsInf",
"IsFinite",
"IsNormal",
"SignBitSet",
"LessOrGreater",
"Ordered",
"Unordered",
"ArrayLength",
"IAdd",
"FAdd",
"ISub",
"FSub",
"IMul",
"FMul",
"UDiv",
"SDiv",
"FDiv",
"UMod",
"SRem",
"SMod",
"FRem",
"FMod",
"VectorTimesScalar",
"MatrixTimesScalar",
"VectorTimesMatrix",
"MatrixTimesVector",
"MatrixTimesMatrix",
"OuterProduct",
"Dot",
"ShiftRightLogical",
"ShiftRightArithmetic",
"ShiftLeftLogical",
"LogicalOr",
"LogicalXor",
"LogicalAnd",
"BitwiseOr",
"BitwiseXor",
"BitwiseAnd",
"Select",
"IEqual",
"FOrdEqual",
"FUnordEqual",
"INotEqual",
"FOrdNotEqual",
"FUnordNotEqual",
"ULessThan",
"SLessThan",
"FOrdLessThan",
"FUnordLessThan",
"UGreaterThan",
"SGreaterThan",
"FOrdGreaterThan",
"FUnordGreaterThan",
"ULessThanEqual",
"SLessThanEqual",
"FOrdLessThanEqual",
"FUnordLessThanEqual",
"UGreaterThanEqual",
"SGreaterThanEqual",
"FOrdGreaterThanEqual",
"FUnordGreaterThanEqual",
"DPdx",
"DPdy",
"Fwidth",
"DPdxFine",
"DPdyFine",
"FwidthFine",
"DPdxCoarse",
"DPdyCoarse",
"FwidthCoarse",
"EmitVertex",
"EndPrimitive",
"EmitStreamVertex",
"EndStreamPrimitive",
"ControlBarrier",
"MemoryBarrier",
"ImagePointer",
"AtomicInit",
"AtomicLoad",
"AtomicStore",
"AtomicExchange",
"AtomicCompareExchange",
"AtomicCompareExchangeWeak",
"AtomicIIncrement",
"AtomicIDecrement",
"AtomicIAdd",
"AtomicISub",
"AtomicUMin",
"AtomicUMax",
"AtomicAnd",
"AtomicOr",
"AtomicXor",
"LoopMerge",
"SelectionMerge",
"Label",
"Branch",
"BranchConditional",
"Switch",
"Kill",
"Return",
"ReturnValue",
"Unreachable",
"LifetimeStart",
"LifetimeStop",
"CompileFlag",
"AsyncGroupCopy",
"WaitGroupEvents",
"GroupAll",
"GroupAny",
"GroupBroadcast",
"GroupIAdd",
"GroupFAdd",
"GroupFMin",
"GroupUMin",
"GroupSMin",
"GroupFMax",
"GroupUMax",
"GroupSMax",
"GenericCastToPtrExplicit",
"GenericPtrMemSemantics",
"ReadPipe",
"WritePipe",
"ReservedReadPipe",
"ReservedWritePipe",
"ReserveReadPipePackets",
"ReserveWritePipePackets",
"CommitReadPipe",
"CommitWritePipe",
"IsValidReserveId",
"GetNumPipePackets",
"GetMaxPipePackets",
"GroupReserveReadPipePackets",
"GroupReserveWritePipePackets",
"GroupCommitReadPipe",
"GroupCommitWritePipe",
"EnqueueMarker",
"EnqueueKernel",
"GetKernelNDrangeSubGroupCount",
"GetKernelNDrangeMaxSubGroupSize",
"GetKernelWorkGroupSize",
"GetKernelPreferredWorkGroupSizeMultiple",
"RetainEvent",
"ReleaseEvent",
"CreateUserEvent",
"IsValidEvent",
"SetUserEventStatus",
"CaptureEventProfilingInfo",
"GetDefaultQueue",
"BuildNDRange",
"SatConvertSToU",
"SatConvertUToS",
"AtomicIMin",
"AtomicIMax",
};
BX_STATIC_ASSERT(BX_COUNTOF(s_spirvOpcode) == SpirvOpcode::Count);
const char* getName(SpirvOpcode::Enum _opcode)
{
BX_CHECK(_opcode < SpirvOpcode::Count, "Unknown opcode id %d.", _opcode);
return s_spirvOpcode[_opcode];
}
int32_t read(bx::ReaderI* _reader, SpirvOperand& _operand)
{
int32_t size = 0;
BX_UNUSED(_operand);
uint32_t token;
size += bx::read(_reader, token);
return size;
}
int32_t read(bx::ReaderI* _reader, SpirvInstruction& _instruction)
{
int32_t size = 0;
uint32_t token;
size += bx::read(_reader, token);
_instruction.opcode = SpirvOpcode::Enum( (token & UINT32_C(0x0000ffff) ) );
_instruction.length = uint16_t( (token & UINT32_C(0xffff0000) ) >> 16);
uint32_t currOp = 0;
const SpirvOpcodeInfo& info = s_sprivOpcodeInfo[_instruction.opcode];
if (0 < info.numValues)
{
size += read(_reader, _instruction.un.value, info.numValues*sizeof(uint32_t) );
}
if (info.hasVariable)
{
while (size/4 != _instruction.length)
{
uint32_t tmp;
size += bx::read(_reader, tmp);
}
}
else
{
_instruction.numOperands = info.numOperands;
switch (info.numOperands)
{
case 6: size += read(_reader, _instruction.operand[currOp++]);
case 5: size += read(_reader, _instruction.operand[currOp++]);
case 4: size += read(_reader, _instruction.operand[currOp++]);
case 3: size += read(_reader, _instruction.operand[currOp++]);
case 2: size += read(_reader, _instruction.operand[currOp++]);
case 1: size += read(_reader, _instruction.operand[currOp++]);
case 0:
break;
default:
BX_WARN(false, "Instruction %s with invalid number of operands %d (numValues %d)."
, getName(_instruction.opcode)
, info.numOperands
, info.numValues
);
break;
}
BX_WARN(size/4 == _instruction.length, "read %d, expected %d, %s"
, size/4
, _instruction.length
, getName(_instruction.opcode)
);
while (size/4 != _instruction.length)
{
uint32_t tmp;
size += bx::read(_reader, tmp);
}
}
return size;
}
int32_t write(bx::WriterI* _writer, const SpirvInstruction& _instruction)
{
int32_t size = 0;
BX_UNUSED(_writer, _instruction);
return size;
}
int32_t toString(char* _out, int32_t _size, const SpirvInstruction& _instruction)
{
int32_t size = 0;
size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
, "%s %d (%d, %d)"
, getName(_instruction.opcode)
, _instruction.numOperands
, _instruction.un.value[0]
, _instruction.un.value[1]
);
return size;
}
int32_t read(bx::ReaderSeekerI* _reader, SpirvShader& _shader)
{
int32_t size = 0;
uint32_t len = uint32_t(bx::getSize(_reader) - bx::seek(_reader) );
_shader.byteCode.resize(len);
size += bx::read(_reader, _shader.byteCode.data(), len);
return size;
}
int32_t write(bx::WriterI* _writer, const SpirvShader& _shader)
{
int32_t size = 0;
BX_UNUSED(_writer, _shader);
return size;
}
#define SPIRV_MAGIC 0x07230203
int32_t read(bx::ReaderSeekerI* _reader, Spirv& _spirv)
{
int32_t size = 0;
size += bx::read(_reader, _spirv.header);
if (size != sizeof(Spirv::Header)
|| _spirv.header.magic != SPIRV_MAGIC
)
{
// error
return -size;
}
size += read(_reader, _spirv.shader);
return size;
}
int32_t write(bx::WriterSeekerI* _writer, const Spirv& _spirv)
{
int32_t size = 0;
BX_UNUSED(_writer, _spirv);
return size;
}
void parse(const SpirvShader& _src, SpirvParseFn _fn, void* _userData)
{
bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
{
SpirvInstruction instruction;
uint32_t size = read(&reader, instruction);
BX_CHECK(size/4 == instruction.length, "read %d, expected %d, %s"
, size/4
, instruction.length
, getName(instruction.opcode)
);
_fn(token * sizeof(uint32_t), instruction, _userData);
token += instruction.length;
}
}
} // namespace bgfx

520
src/shader_spirv.h Normal file
View file

@ -0,0 +1,520 @@
/*
* Copyright 2011-2015 Branimir Karadzic. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
#ifndef BGFX_SHADER_SPIRV_H
#define BGFX_SHADER_SPIRV_H
#include <bx/readerwriter.h>
namespace bgfx
{
// Reference: https://www.khronos.org/registry/spir-v/specs/1.0/SPIRV.html
struct SpirvOpcode
{
enum Enum
{
Nop,
Source,
SourceExtension,
Extension,
ExtInstImport,
MemoryModel,
EntryPoint,
ExecutionMode,
TypeVoid,
TypeBool,
TypeInt,
TypeFloat,
TypeVector,
TypeMatrix,
TypeSampler,
TypeFilter,
TypeArray,
TypeRuntimeArray,
TypeStruct,
TypeOpaque,
TypePointer,
TypeFunction,
TypeEvent,
TypeDeviceEvent,
TypeReserveId,
TypeQueue,
TypePipe,
ConstantTrue,
ConstantFalse,
Constant,
ConstantComposite,
ConstantSampler,
ConstantNullPointer,
ConstantNullObject,
SpecConstantTrue,
SpecConstantFalse,
SpecConstant,
SpecConstantComposite,
Variable,
VariableArray,
Function,
FunctionParameter,
FunctionEnd,
FunctionCall,
ExtInst,
Undef,
Load,
Store,
Phi,
DecorationGroup,
Decorate,
MemberDecorate,
GroupDecorate,
GroupMemberDecorate,
Name,
MemberName,
String,
Line,
VectorExtractDynamic,
VectorInsertDynamic,
VectorShuffle,
CompositeConstruct,
CompositeExtract,
CompositeInsert,
CopyObject,
CopyMemory,
CopyMemorySized,
Sampler,
TextureSample,
TextureSampleDref,
TextureSampleLod,
TextureSampleProj,
TextureSampleGrad,
TextureSampleOffset,
TextureSampleProjLod,
TextureSampleProjGrad,
TextureSampleLodOffset,
TextureSampleProjOffset,
TextureSampleGradOffset,
TextureSampleProjLodOffset,
TextureSampleProjGradOffset,
TextureFetchTexelLod,
TextureFetchTexelOffset,
TextureFetchSample,
TextureFetchTexel,
TextureGather,
TextureGatherOffset,
TextureGatherOffsets,
TextureQuerySizeLod,
TextureQuerySize,
TextureQueryLod,
TextureQueryLevels,
TextureQuerySamples,
AccessChain,
InBoundsAccessChain,
SNegate,
FNegate,
Not,
Any,
All,
ConvertFToU,
ConvertFToS,
ConvertSToF,
ConvertUToF,
UConvert,
SConvert,
FConvert,
ConvertPtrToU,
ConvertUToPtr,
PtrCastToGeneric,
GenericCastToPtr,
Bitcast,
Transpose,
IsNan,
IsInf,
IsFinite,
IsNormal,
SignBitSet,
LessOrGreater,
Ordered,
Unordered,
ArrayLength,
IAdd,
FAdd,
ISub,
FSub,
IMul,
FMul,
UDiv,
SDiv,
FDiv,
UMod,
SRem,
SMod,
FRem,
FMod,
VectorTimesScalar,
MatrixTimesScalar,
VectorTimesMatrix,
MatrixTimesVector,
MatrixTimesMatrix,
OuterProduct,
Dot,
ShiftRightLogical,
ShiftRightArithmetic,
ShiftLeftLogical,
LogicalOr,
LogicalXor,
LogicalAnd,
BitwiseOr,
BitwiseXor,
BitwiseAnd,
Select,
IEqual,
FOrdEqual,
FUnordEqual,
INotEqual,
FOrdNotEqual,
FUnordNotEqual,
ULessThan,
SLessThan,
FOrdLessThan,
FUnordLessThan,
UGreaterThan,
SGreaterThan,
FOrdGreaterThan,
FUnordGreaterThan,
ULessThanEqual,
SLessThanEqual,
FOrdLessThanEqual,
FUnordLessThanEqual,
UGreaterThanEqual,
SGreaterThanEqual,
FOrdGreaterThanEqual,
FUnordGreaterThanEqual,
DPdx,
DPdy,
Fwidth,
DPdxFine,
DPdyFine,
FwidthFine,
DPdxCoarse,
DPdyCoarse,
FwidthCoarse,
EmitVertex,
EndPrimitive,
EmitStreamVertex,
EndStreamPrimitive,
ControlBarrier,
MemoryBarrier,
ImagePointer,
AtomicInit,
AtomicLoad,
AtomicStore,
AtomicExchange,
AtomicCompareExchange,
AtomicCompareExchangeWeak,
AtomicIIncrement,
AtomicIDecrement,
AtomicIAdd,
AtomicISub,
AtomicUMin,
AtomicUMax,
AtomicAnd,
AtomicOr,
AtomicXor,
LoopMerge,
SelectionMerge,
Label,
Branch,
BranchConditional,
Switch,
Kill,
Return,
ReturnValue,
Unreachable,
LifetimeStart,
LifetimeStop,
CompileFlag,
AsyncGroupCopy,
WaitGroupEvents,
GroupAll,
GroupAny,
GroupBroadcast,
GroupIAdd,
GroupFAdd,
GroupFMin,
GroupUMin,
GroupSMin,
GroupFMax,
GroupUMax,
GroupSMax,
GenericCastToPtrExplicit,
GenericPtrMemSemantics,
ReadPipe,
WritePipe,
ReservedReadPipe,
ReservedWritePipe,
ReserveReadPipePackets,
ReserveWritePipePackets,
CommitReadPipe,
CommitWritePipe,
IsValidReserveId,
GetNumPipePackets,
GetMaxPipePackets,
GroupReserveReadPipePackets,
GroupReserveWritePipePackets,
GroupCommitReadPipe,
GroupCommitWritePipe,
EnqueueMarker,
EnqueueKernel,
GetKernelNDrangeSubGroupCount,
GetKernelNDrangeMaxSubGroupSize,
GetKernelWorkGroupSize,
GetKernelPreferredWorkGroupSizeMultiple,
RetainEvent,
ReleaseEvent,
CreateUserEvent,
IsValidEvent,
SetUserEventStatus,
CaptureEventProfilingInfo,
GetDefaultQueue,
BuildNDRange,
SatConvertSToU,
SatConvertUToS,
AtomicIMin,
AtomicIMax,
Count
};
};
struct SpirvBuiltin
{
enum Enum
{
Position,
PointSize,
ClipVertex,
ClipDistance,
CullDistance,
VertexId,
InstanceId,
BuiltInPrimitiveId,
InvocationId,
Layer,
ViewportIndex,
TessLevelOuter,
TessLevelInner,
TessCoord,
PatchVertices,
FragCoord,
PointCoord,
FrontFacing,
SampleId,
SamplePosition,
SampleMask,
FragColor,
FragDepth,
HelperInvocation,
NumWorkgroups,
WorkgroupSize,
WorkgroupId,
LocalInvocationId,
GlobalInvocationId,
LocalInvocationIndex,
WorkDim,
GlobalSize,
EnqueuedWorkgroupSize,
GlobalOffset,
GlobalLinearId,
WorkgroupLinearId,
SubgroupSize,
SubgroupMaxSize,
NumSubgroups,
NumEnqueuedSubgroups,
SubgroupId,
SubgroupLocalInvocationId,
};
};
struct SpirvExecutionModel
{
enum Enum
{
Vertex,
TessellationControl,
TessellationEvaluation,
Geometry,
Fragment,
GLCompute,
Kernel,
Count
};
};
struct SpirvMemoryModel
{
enum Enum
{
Simple,
GLSL450,
OpenCL12,
OpenCL20,
OpenCL21,
Count
};
};
struct SpirvStorageClass
{
enum Enum
{
UniformConstant,
Input,
Uniform,
Output,
WorkgroupLocal,
WorkgroupGlobal,
PrivateGlobal,
Function,
Generic,
Private,
AtomicCounter,
};
};
struct SpirvResourceDim
{
enum Enum
{
Texture1D,
Texture2D,
Texture3D,
TextureCube,
TextureRect,
Buffer,
};
};
struct SpirvDecoration
{
enum Enum
{
PrecisionLow,
PrecisionMedium,
PrecisionHigh,
Block,
BufferBlock,
RowMajor,
ColMajor,
GLSLShared,
GLSLStd140,
GLSLStd430,
GLSLPacked,
Smooth,
Noperspective,
Flat,
Patch,
Centroid,
Sample,
Invariant,
Restrict,
Aliased,
Volatile,
Constant,
Coherent,
Nonwritable,
Nonreadable,
Uniform,
NoStaticUse,
CPacked,
SaturatedConversion,
Stream,
Location,
Component,
Index,
Binding,
DescriptorSet,
Offset,
Alignment,
XfbBuffer,
Stride,
BuiltIn,
FuncParamAttr,
FPRoundingMode,
FPFastMathMode,
LinkageAttributes,
SpecId,
Count
};
};
struct SpirvOperand
{
};
struct SpirvInstruction
{
SpirvOpcode::Enum opcode;
uint16_t length;
uint8_t numOperands;
SpirvOperand operand[6];
union
{
struct ResultTypeId
{
uint32_t resultType;
uint32_t id;
};
ResultTypeId constant;
ResultTypeId constantComposite;
uint32_t value[8];
} un;
};
int32_t read(bx::ReaderI* _reader, SpirvInstruction& _instruction);
int32_t write(bx::WriterI* _writer, const SpirvInstruction& _instruction);
int32_t toString(char* _out, int32_t _size, const SpirvInstruction& _instruction);
struct SpirvShader
{
stl::vector<uint8_t> byteCode;
};
int32_t read(bx::ReaderSeekerI* _reader, SpirvShader& _shader);
int32_t write(bx::WriterI* _writer, const SpirvShader& _shader);
typedef void (*SpirvParseFn)(uint32_t _offset, const SpirvInstruction& _instruction, void* _userData);
void parse(const SpirvShader& _src, SpirvParseFn _fn, void* _userData);
typedef void (*SpirvFilterFn)(SpirvInstruction& _instruction, void* _userData);
void filter(SpirvShader& _dst, const SpirvShader& _src, SpirvFilterFn _fn, void* _userData);
struct Spirv
{
struct Header
{
uint32_t magic;
uint32_t version;
uint32_t generator;
uint32_t bound;
uint32_t schema;
};
Header header;
SpirvShader shader;
};
int32_t read(bx::ReaderSeekerI* _reader, Spirv& _spirv);
int32_t write(bx::WriterSeekerI* _writer, const Spirv& _spirv);
} // namespace bgfx
#endif // BGFX_SHADER_SPIRV_H