mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 07:36:15 +00:00
Initial commit of all the NXT integration.
More like squashed history, contributors were: - Kai Ninomiya - Corentin Wallez
This commit is contained in:
303
src/backend/opengl/CommandBufferGL.cpp
Normal file
303
src/backend/opengl/CommandBufferGL.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "CommandBufferGL.h"
|
||||
|
||||
#include "common/Commands.h"
|
||||
#include "OpenGLBackend.h"
|
||||
#include "PipelineGL.h"
|
||||
#include "PipelineLayoutGL.h"
|
||||
#include "SamplerGL.h"
|
||||
#include "TextureGL.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
|
||||
: CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
|
||||
}
|
||||
|
||||
CommandBuffer::~CommandBuffer() {
|
||||
FreeCommands(&commands);
|
||||
}
|
||||
|
||||
static GLenum IndexFormatType(nxt::IndexFormat format) {
|
||||
switch (format) {
|
||||
case nxt::IndexFormat::Uint16:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case nxt::IndexFormat::Uint32:
|
||||
return GL_UNSIGNED_INT;
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum VertexFormatType(nxt::VertexFormat format) {
|
||||
switch (format) {
|
||||
case nxt::VertexFormat::FloatR32G32B32A32:
|
||||
case nxt::VertexFormat::FloatR32G32B32:
|
||||
case nxt::VertexFormat::FloatR32G32:
|
||||
return GL_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
void CommandBuffer::Execute() {
|
||||
Command type;
|
||||
Pipeline* lastPipeline = nullptr;
|
||||
uint32_t indexBufferOffset = 0;
|
||||
nxt::IndexFormat indexBufferFormat = nxt::IndexFormat::Uint16;
|
||||
|
||||
while(commands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
|
||||
case Command::CopyBufferToTexture:
|
||||
{
|
||||
CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
|
||||
Buffer* buffer = ToBackend(copy->buffer.Get());
|
||||
Texture* texture = ToBackend(copy->texture.Get());
|
||||
GLenum target = texture->GetGLTarget();
|
||||
auto format = texture->GetGLFormat();
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle());
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(target, texture->GetHandle());
|
||||
|
||||
glTexSubImage2D(target, copy->level, copy->x, copy->y, copy->width, copy->height,
|
||||
format.format, format.type, nullptr);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::Dispatch:
|
||||
{
|
||||
DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
|
||||
glDispatchCompute(dispatch->x, dispatch->y, dispatch->z);
|
||||
// TODO(cwallez@chromium.org): add barriers to the API
|
||||
glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::DrawArrays:
|
||||
{
|
||||
DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
|
||||
if (draw->firstInstance > 0) {
|
||||
glDrawArraysInstancedBaseInstance(GL_TRIANGLES,
|
||||
draw->firstVertex, draw->vertexCount, draw->instanceCount, draw->firstInstance);
|
||||
} else {
|
||||
// This branch is only needed on OpenGL < 4.2
|
||||
glDrawArraysInstanced(GL_TRIANGLES,
|
||||
draw->firstVertex, draw->vertexCount, draw->instanceCount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::DrawElements:
|
||||
{
|
||||
DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
|
||||
size_t formatSize = IndexFormatSize(indexBufferFormat);
|
||||
GLenum formatType = IndexFormatType(indexBufferFormat);
|
||||
|
||||
if (draw->firstInstance > 0) {
|
||||
glDrawElementsInstancedBaseInstance(GL_TRIANGLES,
|
||||
draw->indexCount, formatType,
|
||||
reinterpret_cast<void*>(draw->firstIndex * formatSize + indexBufferOffset),
|
||||
draw->instanceCount, draw->firstInstance);
|
||||
} else {
|
||||
// This branch is only needed on OpenGL < 4.2
|
||||
glDrawElementsInstanced(GL_TRIANGLES,
|
||||
draw->indexCount, formatType,
|
||||
reinterpret_cast<void*>(draw->firstIndex * formatSize + indexBufferOffset),
|
||||
draw->instanceCount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetPipeline:
|
||||
{
|
||||
SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
|
||||
ToBackend(cmd->pipeline)->ApplyNow();
|
||||
lastPipeline = ToBackend(cmd->pipeline).Get();
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetPushConstants:
|
||||
{
|
||||
SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
|
||||
uint32_t* valuesUInt = commands.NextData<uint32_t>(cmd->count);
|
||||
int32_t* valuesInt = reinterpret_cast<int32_t*>(valuesUInt);
|
||||
float* valuesFloat = reinterpret_cast<float*>(valuesUInt);
|
||||
|
||||
for (auto stage : IterateStages(cmd->stage)) {
|
||||
const auto& pushConstants = lastPipeline->GetPushConstants(stage);
|
||||
const auto& glPushConstants = lastPipeline->GetGLPushConstants(stage);
|
||||
for (size_t i = 0; i < cmd->count; i++) {
|
||||
GLint location = glPushConstants[cmd->offset + i];
|
||||
|
||||
switch (pushConstants.types[cmd->offset + i]) {
|
||||
case PushConstantType::Int:
|
||||
glUniform1i(location, valuesInt[i]);
|
||||
break;
|
||||
case PushConstantType::UInt:
|
||||
glUniform1ui(location, valuesUInt[i]);
|
||||
break;
|
||||
case PushConstantType::Float:
|
||||
glUniform1f(location, valuesFloat[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetBindGroup:
|
||||
{
|
||||
SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
|
||||
size_t index = cmd->index;
|
||||
BindGroup* group = ToBackend(cmd->group.Get());
|
||||
|
||||
const auto& indices = ToBackend(lastPipeline->GetLayout())->GetBindingIndexInfo()[index];
|
||||
const auto& layout = group->GetLayout()->GetBindingInfo();
|
||||
|
||||
// TODO(cwallez@chromium.org): iterate over the layout bitmask instead
|
||||
for (size_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
||||
if (!layout.mask[binding]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (layout.types[binding]) {
|
||||
case nxt::BindingType::UniformBuffer:
|
||||
{
|
||||
BufferView* view = ToBackend(group->GetBindingAsBufferView(binding));
|
||||
GLuint buffer = ToBackend(view->GetBuffer())->GetHandle();
|
||||
GLuint index = indices[binding];
|
||||
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, index, buffer, view->GetOffset(), view->GetSize());
|
||||
}
|
||||
break;
|
||||
|
||||
case nxt::BindingType::Sampler:
|
||||
{
|
||||
GLuint sampler = ToBackend(group->GetBindingAsSampler(binding))->GetHandle();
|
||||
GLuint index = indices[binding];
|
||||
|
||||
for (auto unit : lastPipeline->GetTextureUnitsForSampler(index)) {
|
||||
glBindSampler(unit, sampler);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nxt::BindingType::SampledTexture:
|
||||
{
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(binding));
|
||||
Texture* texture = ToBackend(view->GetTexture());
|
||||
GLuint handle = texture->GetHandle();
|
||||
GLenum target = texture->GetGLTarget();
|
||||
GLuint index = indices[binding];
|
||||
|
||||
for (auto unit : lastPipeline->GetTextureUnitsForTexture(index)) {
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
glBindTexture(target, handle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nxt::BindingType::StorageBuffer:
|
||||
{
|
||||
BufferView* view = ToBackend(group->GetBindingAsBufferView(binding));
|
||||
GLuint buffer = ToBackend(view->GetBuffer())->GetHandle();
|
||||
GLuint index = indices[binding];
|
||||
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, index, buffer, view->GetOffset(), view->GetSize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetIndexBuffer:
|
||||
{
|
||||
SetIndexBufferCmd* cmd = commands.NextCommand<SetIndexBufferCmd>();
|
||||
|
||||
GLuint buffer = ToBackend(cmd->buffer.Get())->GetHandle();
|
||||
indexBufferOffset = cmd->offset;
|
||||
indexBufferFormat = cmd->format;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::SetVertexBuffers:
|
||||
{
|
||||
SetVertexBuffersCmd* cmd = commands.NextCommand<SetVertexBuffersCmd>();
|
||||
auto buffers = commands.NextData<Ref<BufferBase>>(cmd->count);
|
||||
auto offsets = commands.NextData<uint32_t>(cmd->count);
|
||||
|
||||
auto inputState = lastPipeline->GetInputState();
|
||||
|
||||
auto& attributesSetMask = inputState->GetAttributesSetMask();
|
||||
for (uint32_t location = 0; location < attributesSetMask.size(); ++location) {
|
||||
if (!attributesSetMask[location]) {
|
||||
// This slot is not used in the input state
|
||||
continue;
|
||||
}
|
||||
auto attribute = inputState->GetAttribute(location);
|
||||
auto slot = attribute.bindingSlot;
|
||||
ASSERT(slot < kMaxVertexInputs);
|
||||
if (slot < cmd->startSlot || slot >= cmd->startSlot + cmd->count) {
|
||||
// This slot is not affected by this call
|
||||
continue;
|
||||
}
|
||||
size_t bufferIndex = slot - cmd->startSlot;
|
||||
GLuint buffer = ToBackend(buffers[bufferIndex])->GetHandle();
|
||||
uint32_t bufferOffset = offsets[bufferIndex];
|
||||
|
||||
auto input = inputState->GetInput(slot);
|
||||
|
||||
auto components = VertexFormatNumComponents(attribute.format);
|
||||
auto formatType = VertexFormatType(attribute.format);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glVertexAttribPointer(
|
||||
location, components, formatType, GL_FALSE,
|
||||
input.stride,
|
||||
reinterpret_cast<void*>(static_cast<intptr_t>(bufferOffset + attribute.offset)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::TransitionBufferUsage:
|
||||
{
|
||||
TransitionBufferUsageCmd* cmd = commands.NextCommand<TransitionBufferUsageCmd>();
|
||||
|
||||
cmd->buffer->TransitionUsageImpl(cmd->usage);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::TransitionTextureUsage:
|
||||
{
|
||||
TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
|
||||
|
||||
cmd->texture->TransitionUsageImpl(cmd->usage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: cleanup a tiny bit of state to make this work with
|
||||
// virtualized contexts enabled in Chromium
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
45
src/backend/opengl/CommandBufferGL.h
Normal file
45
src/backend/opengl/CommandBufferGL.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_COMMANDBUFFER_H_
|
||||
#define BACKEND_OPENGL_COMMANDBUFFER_H_
|
||||
|
||||
#include "common/CommandAllocator.h"
|
||||
#include "common/CommandBuffer.h"
|
||||
|
||||
namespace backend {
|
||||
class CommandBufferBuilder;
|
||||
}
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
|
||||
class CommandBuffer : public CommandBufferBase {
|
||||
public:
|
||||
CommandBuffer(Device* device, CommandBufferBuilder* builder);
|
||||
~CommandBuffer();
|
||||
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
CommandIterator commands;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_COMMANDBUFFER_H_
|
||||
21
src/backend/opengl/GeneratedCodeIncludes.h
Normal file
21
src/backend/opengl/GeneratedCodeIncludes.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "OpenGLBackend.h"
|
||||
#include "CommandBufferGL.h"
|
||||
#include "PipelineGL.h"
|
||||
#include "PipelineLayoutGL.h"
|
||||
#include "SamplerGL.h"
|
||||
#include "ShaderModuleGL.h"
|
||||
#include "TextureGL.h"
|
||||
180
src/backend/opengl/OpenGLBackend.cpp
Normal file
180
src/backend/opengl/OpenGLBackend.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "OpenGLBackend.h"
|
||||
|
||||
#include "CommandBufferGL.h"
|
||||
#include "PipelineGL.h"
|
||||
#include "PipelineLayoutGL.h"
|
||||
#include "ShaderModuleGL.h"
|
||||
#include "SamplerGL.h"
|
||||
#include "TextureGL.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
nxtProcTable GetNonValidatingProcs();
|
||||
nxtProcTable GetValidatingProcs();
|
||||
|
||||
void HACKCLEAR() {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
|
||||
*device = nullptr;
|
||||
|
||||
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(getProc));
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
HACKCLEAR();
|
||||
|
||||
*procs = GetValidatingProcs();
|
||||
*device = reinterpret_cast<nxtDevice>(new Device);
|
||||
}
|
||||
|
||||
// Device
|
||||
|
||||
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
||||
return new BindGroup(this, builder);
|
||||
}
|
||||
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) {
|
||||
return new BindGroupLayout(this, builder);
|
||||
}
|
||||
BufferBase* Device::CreateBuffer(BufferBuilder* builder) {
|
||||
return new Buffer(this, builder);
|
||||
}
|
||||
BufferViewBase* Device::CreateBufferView(BufferViewBuilder* builder) {
|
||||
return new BufferView(this, builder);
|
||||
}
|
||||
CommandBufferBase* Device::CreateCommandBuffer(CommandBufferBuilder* builder) {
|
||||
return new CommandBuffer(this, builder);
|
||||
}
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(this, builder);
|
||||
}
|
||||
PipelineBase* Device::CreatePipeline(PipelineBuilder* builder) {
|
||||
return new Pipeline(this, builder);
|
||||
}
|
||||
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
|
||||
return new PipelineLayout(this, builder);
|
||||
}
|
||||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(this, builder);
|
||||
}
|
||||
SamplerBase* Device::CreateSampler(SamplerBuilder* builder) {
|
||||
return new Sampler(this, builder);
|
||||
}
|
||||
ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) {
|
||||
return new ShaderModule(this, builder);
|
||||
}
|
||||
TextureBase* Device::CreateTexture(TextureBuilder* builder) {
|
||||
return new Texture(this, builder);
|
||||
}
|
||||
TextureViewBase* Device::CreateTextureView(TextureViewBuilder* builder) {
|
||||
return new TextureView(this, builder);
|
||||
}
|
||||
|
||||
void Device::Reference() {
|
||||
}
|
||||
|
||||
void Device::Release() {
|
||||
}
|
||||
|
||||
// Bind Group
|
||||
|
||||
BindGroup::BindGroup(Device* device, BindGroupBuilder* builder)
|
||||
: BindGroupBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// Bind Group Layout
|
||||
|
||||
BindGroupLayout::BindGroupLayout(Device* device, BindGroupLayoutBuilder* builder)
|
||||
: BindGroupLayoutBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// Buffer
|
||||
|
||||
Buffer::Buffer(Device* device, BufferBuilder* builder)
|
||||
: BufferBase(builder), device(device) {
|
||||
glGenBuffers(1, &buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
GLuint Buffer::GetHandle() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, start * sizeof(uint32_t), count * sizeof(uint32_t), data);
|
||||
}
|
||||
|
||||
// BufferView
|
||||
|
||||
BufferView::BufferView(Device* device, BufferViewBuilder* builder)
|
||||
: BufferViewBase(builder), device(device) {
|
||||
}
|
||||
|
||||
// InputState
|
||||
|
||||
InputState::InputState(Device* device, InputStateBuilder* builder)
|
||||
: InputStateBase(builder), device(device) {
|
||||
glGenVertexArrays(1, &vertexArrayObject);
|
||||
glBindVertexArray(vertexArrayObject);
|
||||
auto& attributesSetMask = GetAttributesSetMask();
|
||||
for (uint32_t location = 0; location < attributesSetMask.size(); ++location) {
|
||||
if (!attributesSetMask[location]) {
|
||||
continue;
|
||||
}
|
||||
auto attribute = GetAttribute(location);
|
||||
glEnableVertexAttribArray(location);
|
||||
|
||||
auto input = GetInput(attribute.bindingSlot);
|
||||
if (input.stride == 0) {
|
||||
// Emulate a stride of zero (constant vertex attribute) by
|
||||
// setting the attribute instance divisor to a huge number.
|
||||
glVertexAttribDivisor(location, 0xffffffff);
|
||||
} else {
|
||||
switch (input.stepMode) {
|
||||
case nxt::InputStepMode::Vertex:
|
||||
break;
|
||||
case nxt::InputStepMode::Instance:
|
||||
glVertexAttribDivisor(location, 1);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLuint InputState::GetVAO() {
|
||||
return vertexArrayObject;
|
||||
}
|
||||
|
||||
// Queue
|
||||
|
||||
Queue::Queue(Device* device, QueueBuilder* builder) : device(device) {
|
||||
}
|
||||
|
||||
void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) {
|
||||
for (uint32_t i = 0; i < numCommands; ++i) {
|
||||
commands[i]->Execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
151
src/backend/opengl/OpenGLBackend.h
Normal file
151
src/backend/opengl/OpenGLBackend.h
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_OPENGLBACKEND_H_
|
||||
#define BACKEND_OPENGL_OPENGLBACKEND_H_
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include "common/Buffer.h"
|
||||
#include "common/BindGroup.h"
|
||||
#include "common/BindGroupLayout.h"
|
||||
#include "common/Device.h"
|
||||
#include "common/InputState.h"
|
||||
#include "common/Queue.h"
|
||||
#include "common/ToBackend.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class BindGroup;
|
||||
class BindGroupLayout;
|
||||
class Buffer;
|
||||
class BufferView;
|
||||
class CommandBuffer;
|
||||
class InputState;
|
||||
class Pipeline;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
class Texture;
|
||||
class TextureView;
|
||||
|
||||
struct OpenGLBackendTraits {
|
||||
using BindGroupType = BindGroup;
|
||||
using BindGroupLayoutType = BindGroupLayout;
|
||||
using BufferType = Buffer;
|
||||
using BufferViewType = BufferView;
|
||||
using CommandBufferType = CommandBuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineType = Pipeline;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
using TextureType = Texture;
|
||||
using TextureViewType = TextureView;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto ToBackend(T&& common) -> decltype(ToBackendBase<OpenGLBackendTraits>(common)) {
|
||||
return ToBackendBase<OpenGLBackendTraits>(common);
|
||||
}
|
||||
|
||||
// Definition of backend types
|
||||
class Device : public DeviceBase {
|
||||
public:
|
||||
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
|
||||
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
|
||||
BufferBase* CreateBuffer(BufferBuilder* builder) override;
|
||||
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
|
||||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
PipelineBase* CreatePipeline(PipelineBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
TextureBase* CreateTexture(TextureBuilder* builder) override;
|
||||
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
|
||||
|
||||
// NXT API
|
||||
void Reference();
|
||||
void Release();
|
||||
};
|
||||
|
||||
class BindGroup : public BindGroupBase {
|
||||
public:
|
||||
BindGroup(Device* device, BindGroupBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class BindGroupLayout : public BindGroupLayoutBase {
|
||||
public:
|
||||
BindGroupLayout(Device* device, BindGroupLayoutBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class Buffer : public BufferBase {
|
||||
public:
|
||||
Buffer(Device* device, BufferBuilder* builder);
|
||||
|
||||
GLuint GetHandle() const;
|
||||
|
||||
private:
|
||||
void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
|
||||
|
||||
Device* device;
|
||||
GLuint buffer = 0;
|
||||
};
|
||||
|
||||
class BufferView : public BufferViewBase {
|
||||
public:
|
||||
BufferView(Device* device, BufferViewBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
class InputState : public InputStateBase {
|
||||
public:
|
||||
InputState(Device* device, InputStateBuilder* builder);
|
||||
GLuint GetVAO();
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
GLuint vertexArrayObject;
|
||||
};
|
||||
|
||||
class Queue : public QueueBase {
|
||||
public:
|
||||
Queue(Device* device, QueueBuilder* builder);
|
||||
|
||||
// NXT API
|
||||
void Submit(uint32_t numCommands, CommandBuffer* const * commands);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_OPENGLBACKEND_H_
|
||||
213
src/backend/opengl/PipelineGL.cpp
Normal file
213
src/backend/opengl/PipelineGL.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "PipelineGL.h"
|
||||
|
||||
#include "OpenGLBackend.h"
|
||||
#include "PipelineLayoutGL.h"
|
||||
#include "ShaderModuleGL.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
namespace {
|
||||
|
||||
GLenum GLShaderType(nxt::ShaderStage stage) {
|
||||
switch (stage) {
|
||||
case nxt::ShaderStage::Vertex:
|
||||
return GL_VERTEX_SHADER;
|
||||
case nxt::ShaderStage::Fragment:
|
||||
return GL_FRAGMENT_SHADER;
|
||||
case nxt::ShaderStage::Compute:
|
||||
return GL_COMPUTE_SHADER;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Pipeline::Pipeline(Device* device, PipelineBuilder* builder) : PipelineBase(builder), device(device) {
|
||||
auto CreateShader = [](GLenum type, const char* source) -> GLuint {
|
||||
GLuint shader = glCreateShader(type);
|
||||
glShaderSource(shader, 1, &source, nullptr);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint compileStatus = GL_FALSE;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
|
||||
if (compileStatus == GL_FALSE) {
|
||||
GLint infoLogLength = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
|
||||
if (infoLogLength > 1) {
|
||||
std::vector<char> buffer(infoLogLength);
|
||||
glGetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
|
||||
std::cout << source << std::endl;
|
||||
std::cout << "Program compilation failed:\n";
|
||||
std::cout << buffer.data() << std::endl;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
};
|
||||
|
||||
auto FillPushConstants = [](const ShaderModule* module, GLPushConstantInfo* info, GLuint program) {
|
||||
const auto& moduleInfo = module->GetPushConstants();
|
||||
for (uint32_t i = 0; i < moduleInfo.names.size(); i++) {
|
||||
(*info)[i] = -1;
|
||||
|
||||
unsigned int size = moduleInfo.sizes[i];
|
||||
if (size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GLint location = glGetUniformLocation(program, moduleInfo.names[i].c_str());
|
||||
if (location == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t offset = 0; offset < size; offset++) {
|
||||
(*info)[i + offset] = location + offset;
|
||||
}
|
||||
i += size - 1;
|
||||
}
|
||||
};
|
||||
|
||||
program = glCreateProgram();
|
||||
|
||||
for (auto stage : IterateStages(GetStageMask())) {
|
||||
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
|
||||
|
||||
GLuint shader = CreateShader(GLShaderType(stage), module->GetSource());
|
||||
glAttachShader(program, shader);
|
||||
}
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus == GL_FALSE) {
|
||||
GLint infoLogLength = 0;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
|
||||
if (infoLogLength > 1) {
|
||||
std::vector<char> buffer(infoLogLength);
|
||||
glGetProgramInfoLog(program, infoLogLength, nullptr, &buffer[0]);
|
||||
std::cout << "Program link failed:\n";
|
||||
std::cout << buffer.data() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto stage : IterateStages(GetStageMask())) {
|
||||
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
|
||||
FillPushConstants(module, &glPushConstants[stage], program);
|
||||
}
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
// The uniforms are part of the program state so we can pre-bind buffer units, texture units etc.
|
||||
const auto& layout = ToBackend(GetLayout());
|
||||
const auto& indices = layout->GetBindingIndexInfo();
|
||||
|
||||
for (uint32_t group = 0; group < kMaxBindGroups; ++group) {
|
||||
const auto& groupInfo = layout->GetBindGroupLayout(group)->GetBindingInfo();
|
||||
|
||||
for (uint32_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
||||
if (!groupInfo.mask[binding]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = GetBindingName(group, binding);
|
||||
switch (groupInfo.types[binding]) {
|
||||
case nxt::BindingType::UniformBuffer:
|
||||
{
|
||||
GLint location = glGetUniformBlockIndex(program, name.c_str());
|
||||
glUniformBlockBinding(program, location, indices[group][binding]);
|
||||
}
|
||||
break;
|
||||
|
||||
case nxt::BindingType::StorageBuffer:
|
||||
{
|
||||
GLuint location = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, name.c_str());
|
||||
glShaderStorageBlockBinding(program, location, indices[group][binding]);
|
||||
}
|
||||
break;
|
||||
|
||||
case nxt::BindingType::Sampler:
|
||||
case nxt::BindingType::SampledTexture:
|
||||
// These binding types are handled in the separate sampler and texture emulation
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute links between stages for combined samplers, then bind them to texture units
|
||||
{
|
||||
std::set<CombinedSampler> combinedSamplersSet;
|
||||
for (auto stage : IterateStages(GetStageMask())) {
|
||||
const auto& module = ToBackend(builder->GetStageInfo(stage).module);
|
||||
|
||||
for (const auto& combined : module->GetCombinedSamplerInfo()) {
|
||||
combinedSamplersSet.insert(combined);
|
||||
}
|
||||
}
|
||||
|
||||
unitsForSamplers.resize(layout->GetNumSamplers());
|
||||
unitsForTextures.resize(layout->GetNumSampledTextures());
|
||||
|
||||
GLuint textureUnit = layout->GetTextureUnitsUsed();
|
||||
for (const auto& combined : combinedSamplersSet) {
|
||||
std::string name = combined.GetName();
|
||||
GLint location = glGetUniformLocation(program, name.c_str());
|
||||
glUniform1i(location, textureUnit);
|
||||
|
||||
GLuint samplerIndex = indices[combined.samplerLocation.group][combined.samplerLocation.binding];
|
||||
unitsForSamplers[samplerIndex].push_back(textureUnit);
|
||||
|
||||
GLuint textureIndex = indices[combined.textureLocation.group][combined.textureLocation.binding];
|
||||
unitsForTextures[textureIndex].push_back(textureUnit);
|
||||
|
||||
textureUnit ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Pipeline::GLPushConstantInfo& Pipeline::GetGLPushConstants(nxt::ShaderStage stage) const {
|
||||
return glPushConstants[stage];
|
||||
}
|
||||
|
||||
const std::vector<GLuint>& Pipeline::GetTextureUnitsForSampler(GLuint index) const {
|
||||
ASSERT(index >= 0 && index < unitsForSamplers.size());
|
||||
return unitsForSamplers[index];
|
||||
}
|
||||
|
||||
const std::vector<GLuint>& Pipeline::GetTextureUnitsForTexture(GLuint index) const {
|
||||
ASSERT(index >= 0 && index < unitsForSamplers.size());
|
||||
return unitsForTextures[index];
|
||||
}
|
||||
|
||||
GLuint Pipeline::GetProgramHandle() const {
|
||||
return program;
|
||||
}
|
||||
|
||||
void Pipeline::ApplyNow() {
|
||||
glUseProgram(program);
|
||||
|
||||
auto inputState = ToBackend(GetInputState());
|
||||
glBindVertexArray(inputState->GetVAO());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
55
src/backend/opengl/PipelineGL.h
Normal file
55
src/backend/opengl/PipelineGL.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_PIPELINEGL_H_
|
||||
#define BACKEND_OPENGL_PIPELINEGL_H_
|
||||
|
||||
#include "common/Pipeline.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
class ShaderModule;
|
||||
|
||||
class Pipeline : public PipelineBase {
|
||||
public:
|
||||
Pipeline(Device* device, PipelineBuilder* builder);
|
||||
|
||||
using GLPushConstantInfo = std::array<GLint, kMaxPushConstants>;
|
||||
using BindingLocations = std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>;
|
||||
|
||||
const GLPushConstantInfo& GetGLPushConstants(nxt::ShaderStage stage) const;
|
||||
const std::vector<GLuint>& GetTextureUnitsForSampler(GLuint index) const;
|
||||
const std::vector<GLuint>& GetTextureUnitsForTexture(GLuint index) const;
|
||||
GLuint GetProgramHandle() const;
|
||||
|
||||
void ApplyNow();
|
||||
|
||||
private:
|
||||
GLuint program;
|
||||
PerStage<GLPushConstantInfo> glPushConstants;
|
||||
std::vector<std::vector<GLuint>> unitsForSamplers;
|
||||
std::vector<std::vector<GLuint>> unitsForTextures;
|
||||
Device* device;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_PIPELINEGL_H_
|
||||
80
src/backend/opengl/PipelineLayoutGL.cpp
Normal file
80
src/backend/opengl/PipelineLayoutGL.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "PipelineLayoutGL.h"
|
||||
|
||||
#include "OpenGLBackend.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
PipelineLayout::PipelineLayout(Device* device, PipelineLayoutBuilder* builder)
|
||||
: PipelineLayoutBase(builder), device(device) {
|
||||
GLuint uboIndex = 0;
|
||||
GLuint samplerIndex = 0;
|
||||
GLuint sampledTextureIndex = 0;
|
||||
GLuint ssboIndex = 0;
|
||||
|
||||
for (size_t group = 0; group < kMaxBindGroups; ++group) {
|
||||
const auto& groupInfo = GetBindGroupLayout(group)->GetBindingInfo();
|
||||
|
||||
for (size_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
||||
if (!groupInfo.mask[binding]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (groupInfo.types[binding]) {
|
||||
case nxt::BindingType::UniformBuffer:
|
||||
indexInfo[group][binding] = uboIndex;
|
||||
uboIndex ++;
|
||||
break;
|
||||
case nxt::BindingType::Sampler:
|
||||
indexInfo[group][binding] = samplerIndex;
|
||||
samplerIndex ++;
|
||||
break;
|
||||
case nxt::BindingType::SampledTexture:
|
||||
indexInfo[group][binding] = sampledTextureIndex;
|
||||
sampledTextureIndex ++;
|
||||
break;
|
||||
|
||||
case nxt::BindingType::StorageBuffer:
|
||||
indexInfo[group][binding] = ssboIndex;
|
||||
ssboIndex ++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numSamplers = samplerIndex;
|
||||
numSampledTextures = sampledTextureIndex;
|
||||
}
|
||||
|
||||
const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo() const {
|
||||
return indexInfo;
|
||||
}
|
||||
|
||||
GLuint PipelineLayout::GetTextureUnitsUsed() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t PipelineLayout::GetNumSamplers() const {
|
||||
return numSamplers;
|
||||
}
|
||||
|
||||
size_t PipelineLayout::GetNumSampledTextures() const {
|
||||
return numSampledTextures;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
48
src/backend/opengl/PipelineLayoutGL.h
Normal file
48
src/backend/opengl/PipelineLayoutGL.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_PIPELINELAYOUTGL_H_
|
||||
#define BACKEND_OPENGL_PIPELINELAYOUTGL_H_
|
||||
|
||||
#include "common/PipelineLayout.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
|
||||
class PipelineLayout : public PipelineLayoutBase {
|
||||
public:
|
||||
PipelineLayout(Device* device, PipelineLayoutBuilder* builder);
|
||||
|
||||
using BindingIndexInfo = std::array<std::array<GLuint, kMaxBindingsPerGroup>, kMaxBindGroups>;
|
||||
const BindingIndexInfo& GetBindingIndexInfo() const;
|
||||
|
||||
GLuint GetTextureUnitsUsed() const;
|
||||
size_t GetNumSamplers() const;
|
||||
size_t GetNumSampledTextures() const;
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
BindingIndexInfo indexInfo;
|
||||
size_t numSamplers;
|
||||
size_t numSampledTextures;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_PIPELINELAYOUTGL_H_
|
||||
62
src/backend/opengl/SamplerGL.cpp
Normal file
62
src/backend/opengl/SamplerGL.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "SamplerGL.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
namespace {
|
||||
GLenum MagFilterMode(nxt::FilterMode filter) {
|
||||
switch (filter) {
|
||||
case nxt::FilterMode::Nearest:
|
||||
return GL_NEAREST;
|
||||
case nxt::FilterMode::Linear:
|
||||
return GL_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum MinFilterMode(nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter) {
|
||||
switch (minFilter) {
|
||||
case nxt::FilterMode::Nearest:
|
||||
switch (mipMapFilter) {
|
||||
case nxt::FilterMode::Nearest:
|
||||
return GL_NEAREST_MIPMAP_NEAREST;
|
||||
case nxt::FilterMode::Linear:
|
||||
return GL_NEAREST_MIPMAP_LINEAR;
|
||||
}
|
||||
case nxt::FilterMode::Linear:
|
||||
switch (mipMapFilter) {
|
||||
case nxt::FilterMode::Nearest:
|
||||
return GL_LINEAR_MIPMAP_NEAREST;
|
||||
case nxt::FilterMode::Linear:
|
||||
return GL_LINEAR_MIPMAP_LINEAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sampler::Sampler(Device* device, SamplerBuilder* builder)
|
||||
: SamplerBase(builder), device(device) {
|
||||
glGenSamplers(1, &handle);
|
||||
glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, MagFilterMode(builder->GetMagFilter()));
|
||||
glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, MinFilterMode(builder->GetMinFilter(), builder->GetMipMapFilter()));
|
||||
}
|
||||
|
||||
GLuint Sampler::GetHandle() const {
|
||||
return handle;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
41
src/backend/opengl/SamplerGL.h
Normal file
41
src/backend/opengl/SamplerGL.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_SAMPLERGL_H_
|
||||
#define BACKEND_OPENGL_SAMPLERGL_H_
|
||||
|
||||
#include "common/Sampler.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
|
||||
class Sampler : public SamplerBase {
|
||||
public:
|
||||
Sampler(Device* device, SamplerBuilder* builder);
|
||||
|
||||
GLuint GetHandle() const;
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
GLuint handle;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_SAMPLERGL_H_
|
||||
105
src/backend/opengl/ShaderModuleGL.cpp
Normal file
105
src/backend/opengl/ShaderModuleGL.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "ShaderModuleGL.h"
|
||||
|
||||
#include <spirv-cross/spirv_glsl.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
std::string GetBindingName(uint32_t group, uint32_t binding) {
|
||||
std::ostringstream o;
|
||||
o << "nxt_binding_" << group << "_" << binding;
|
||||
return o.str();
|
||||
}
|
||||
|
||||
bool operator < (const BindingLocation& a, const BindingLocation& b) {
|
||||
return std::tie(a.group, a.binding) < std::tie(b.group, b.binding);
|
||||
}
|
||||
|
||||
bool operator < (const CombinedSampler& a, const CombinedSampler& b) {
|
||||
return std::tie(a.samplerLocation, a.textureLocation) < std::tie(b.samplerLocation, b.textureLocation);
|
||||
}
|
||||
|
||||
std::string CombinedSampler::GetName() const {
|
||||
std::ostringstream o;
|
||||
o << "nxt_combined";
|
||||
o << "_" << samplerLocation.group << "_" << samplerLocation.binding;
|
||||
o << "_with_" << textureLocation.group << "_" << textureLocation.binding;
|
||||
return o.str();
|
||||
}
|
||||
|
||||
ShaderModule::ShaderModule(Device* device, ShaderModuleBuilder* builder)
|
||||
: ShaderModuleBase(builder), device(device) {
|
||||
spirv_cross::CompilerGLSL compiler(builder->AcquireSpirv());
|
||||
spirv_cross::CompilerGLSL::Options options;
|
||||
|
||||
// TODO(cwallez@chromium.org): discover the backing context version and use that.
|
||||
#if defined(__APPLE__)
|
||||
options.version = 410;
|
||||
#else
|
||||
options.version = 450;
|
||||
#endif
|
||||
compiler.set_options(options);
|
||||
|
||||
ExtractSpirvInfo(compiler);
|
||||
|
||||
const auto& bindingInfo = GetBindingInfo();
|
||||
|
||||
// Extract bindings names so that it can be used to get its location in program.
|
||||
// Now translate the separate sampler / textures into combined ones and store their info.
|
||||
// We need to do this before removing the set and binding decorations.
|
||||
compiler.build_combined_image_samplers();
|
||||
|
||||
for (const auto& combined : compiler.get_combined_image_samplers()) {
|
||||
combinedInfo.emplace_back();
|
||||
|
||||
auto& info = combinedInfo.back();
|
||||
info.samplerLocation.group = compiler.get_decoration(combined.sampler_id, spv::DecorationDescriptorSet);
|
||||
info.samplerLocation.binding = compiler.get_decoration(combined.sampler_id, spv::DecorationBinding);
|
||||
info.textureLocation.group = compiler.get_decoration(combined.image_id, spv::DecorationDescriptorSet);
|
||||
info.textureLocation.binding = compiler.get_decoration(combined.image_id, spv::DecorationBinding);
|
||||
compiler.set_name(combined.combined_id, info.GetName());
|
||||
}
|
||||
|
||||
// Change binding names to be "nxt_binding_<group>_<binding>".
|
||||
// Also unsets the SPIRV "Binding" decoration as it outputs "layout(binding=)" which
|
||||
// isn't supported on OSX's OpenGL.
|
||||
for (uint32_t group = 0; group < kMaxBindGroups; ++group) {
|
||||
for (uint32_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
||||
const auto& info = bindingInfo[group][binding];
|
||||
if (info.used) {
|
||||
compiler.set_name(info.base_type_id, GetBindingName(group, binding));
|
||||
compiler.unset_decoration(info.id, spv::DecorationBinding);
|
||||
compiler.unset_decoration(info.id, spv::DecorationDescriptorSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glslSource = compiler.compile();
|
||||
}
|
||||
|
||||
const char* ShaderModule::GetSource() const {
|
||||
return reinterpret_cast<const char*>(glslSource.data());
|
||||
}
|
||||
|
||||
const ShaderModule::CombinedSamplerInfo& ShaderModule::GetCombinedSamplerInfo() const {
|
||||
return combinedInfo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
60
src/backend/opengl/ShaderModuleGL.h
Normal file
60
src/backend/opengl/ShaderModuleGL.h
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_SHADERMODULEGL_H_
|
||||
#define BACKEND_OPENGL_SHADERMODULEGL_H_
|
||||
|
||||
#include "common/ShaderModule.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
|
||||
std::string GetBindingName(uint32_t group, uint32_t binding);
|
||||
|
||||
struct BindingLocation {
|
||||
uint32_t group;
|
||||
uint32_t binding;
|
||||
};
|
||||
bool operator < (const BindingLocation& a, const BindingLocation& b);
|
||||
|
||||
struct CombinedSampler {
|
||||
BindingLocation samplerLocation;
|
||||
BindingLocation textureLocation;
|
||||
std::string GetName() const;
|
||||
};
|
||||
bool operator < (const CombinedSampler& a, const CombinedSampler& b);
|
||||
|
||||
class ShaderModule : public ShaderModuleBase {
|
||||
public:
|
||||
ShaderModule(Device* device, ShaderModuleBuilder* builder);
|
||||
|
||||
using CombinedSamplerInfo = std::vector<CombinedSampler>;
|
||||
|
||||
const char* GetSource() const;
|
||||
const CombinedSamplerInfo& GetCombinedSamplerInfo() const;
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
CombinedSamplerInfo combinedInfo;
|
||||
std::string glslSource;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_SHADERMODULEGL_H_
|
||||
86
src/backend/opengl/TextureGL.cpp
Normal file
86
src/backend/opengl/TextureGL.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#include "TextureGL.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
namespace {
|
||||
|
||||
GLenum TargetForDimension(nxt::TextureDimension dimension) {
|
||||
switch (dimension) {
|
||||
case nxt::TextureDimension::e2D:
|
||||
return GL_TEXTURE_2D;
|
||||
}
|
||||
}
|
||||
|
||||
TextureFormatInfo GetGLFormatInfo(nxt::TextureFormat format) {
|
||||
switch (format) {
|
||||
case nxt::TextureFormat::R8G8B8A8Unorm:
|
||||
return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Texture
|
||||
|
||||
Texture::Texture(Device* device, TextureBuilder* builder)
|
||||
: TextureBase(builder), device(device) {
|
||||
target = TargetForDimension(GetDimension());
|
||||
|
||||
uint32_t width = GetWidth();
|
||||
uint32_t height = GetHeight();
|
||||
uint32_t levels = GetNumMipLevels();
|
||||
|
||||
auto formatInfo = GetGLFormatInfo(GetFormat());
|
||||
|
||||
glGenTextures(1, &handle);
|
||||
glBindTexture(target, handle);
|
||||
|
||||
for (uint32_t i = 0; i < levels; ++i) {
|
||||
glTexImage2D(target, i, formatInfo.internalFormat, width, height, 0, formatInfo.format, formatInfo.type, nullptr);
|
||||
width = std::max(uint32_t(1), width / 2);
|
||||
height = std::max(uint32_t(1), height / 2);
|
||||
}
|
||||
|
||||
// The texture is not complete if it uses mipmapping and not all levels up to
|
||||
// MAX_LEVEL have been defined.
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels - 1);
|
||||
}
|
||||
|
||||
GLuint Texture::GetHandle() const {
|
||||
return handle;
|
||||
}
|
||||
|
||||
GLenum Texture::GetGLTarget() const {
|
||||
return target;
|
||||
}
|
||||
|
||||
TextureFormatInfo Texture::GetGLFormat() const {
|
||||
return GetGLFormatInfo(GetFormat());
|
||||
}
|
||||
|
||||
// TextureView
|
||||
|
||||
TextureView::TextureView(Device* device, TextureViewBuilder* builder)
|
||||
: TextureViewBase(builder), device(device) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
59
src/backend/opengl/TextureGL.h
Normal file
59
src/backend/opengl/TextureGL.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2017 The NXT 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.
|
||||
|
||||
#ifndef BACKEND_OPENGL_TEXTUREGL_H_
|
||||
#define BACKEND_OPENGL_TEXTUREGL_H_
|
||||
|
||||
#include "common/Texture.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
|
||||
class Device;
|
||||
|
||||
struct TextureFormatInfo {
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
class Texture : public TextureBase {
|
||||
public:
|
||||
Texture(Device* device, TextureBuilder* builder);
|
||||
|
||||
GLuint GetHandle() const;
|
||||
GLenum GetGLTarget() const;
|
||||
TextureFormatInfo GetGLFormat() const;
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
GLuint handle;
|
||||
GLenum target;
|
||||
};
|
||||
|
||||
class TextureView : public TextureViewBase {
|
||||
public:
|
||||
TextureView(Device* device, TextureViewBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_OPENGL_TEXTUREGL_H_
|
||||
Reference in New Issue
Block a user