Move src/backend to src/dawn_native

This commit is contained in:
Corentin Wallez
2018-07-24 13:53:51 +02:00
committed by Corentin Wallez
parent ff9626c751
commit d37523fbde
242 changed files with 865 additions and 865 deletions

View File

@@ -0,0 +1,96 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/BlendStateGL.h"
#include "common/Assert.h"
namespace backend { namespace opengl {
namespace {
GLenum GLBlendFactor(dawn::BlendFactor factor, bool alpha) {
switch (factor) {
case dawn::BlendFactor::Zero:
return GL_ZERO;
case dawn::BlendFactor::One:
return GL_ONE;
case dawn::BlendFactor::SrcColor:
return GL_SRC_COLOR;
case dawn::BlendFactor::OneMinusSrcColor:
return GL_ONE_MINUS_SRC_COLOR;
case dawn::BlendFactor::SrcAlpha:
return GL_SRC_ALPHA;
case dawn::BlendFactor::OneMinusSrcAlpha:
return GL_ONE_MINUS_SRC_ALPHA;
case dawn::BlendFactor::DstColor:
return GL_DST_COLOR;
case dawn::BlendFactor::OneMinusDstColor:
return GL_ONE_MINUS_DST_COLOR;
case dawn::BlendFactor::DstAlpha:
return GL_DST_ALPHA;
case dawn::BlendFactor::OneMinusDstAlpha:
return GL_ONE_MINUS_DST_ALPHA;
case dawn::BlendFactor::SrcAlphaSaturated:
return GL_SRC_ALPHA_SATURATE;
case dawn::BlendFactor::BlendColor:
return alpha ? GL_CONSTANT_ALPHA : GL_CONSTANT_COLOR;
case dawn::BlendFactor::OneMinusBlendColor:
return alpha ? GL_ONE_MINUS_CONSTANT_ALPHA : GL_ONE_MINUS_CONSTANT_COLOR;
default:
UNREACHABLE();
}
}
GLenum GLBlendMode(dawn::BlendOperation operation) {
switch (operation) {
case dawn::BlendOperation::Add:
return GL_FUNC_ADD;
case dawn::BlendOperation::Subtract:
return GL_FUNC_SUBTRACT;
case dawn::BlendOperation::ReverseSubtract:
return GL_FUNC_REVERSE_SUBTRACT;
case dawn::BlendOperation::Min:
return GL_MIN;
case dawn::BlendOperation::Max:
return GL_MAX;
default:
UNREACHABLE();
}
}
} // namespace
BlendState::BlendState(BlendStateBuilder* builder) : BlendStateBase(builder) {
}
void BlendState::ApplyNow(uint32_t attachment) {
const auto& info = GetBlendInfo();
if (info.blendEnabled) {
glEnablei(GL_BLEND, attachment);
glBlendEquationSeparatei(attachment, GLBlendMode(info.colorBlend.operation),
GLBlendMode(info.alphaBlend.operation));
glBlendFuncSeparatei(attachment, GLBlendFactor(info.colorBlend.srcFactor, false),
GLBlendFactor(info.colorBlend.dstFactor, false),
GLBlendFactor(info.alphaBlend.srcFactor, true),
GLBlendFactor(info.alphaBlend.dstFactor, true));
} else {
glDisablei(GL_BLEND, attachment);
}
glColorMaski(attachment, info.colorWriteMask & dawn::ColorWriteMask::Red,
info.colorWriteMask & dawn::ColorWriteMask::Green,
info.colorWriteMask & dawn::ColorWriteMask::Blue,
info.colorWriteMask & dawn::ColorWriteMask::Alpha);
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,33 @@
// Copyright 2017 The Dawn 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_BLENDSTATEGL_H_
#define BACKEND_OPENGL_BLENDSTATEGL_H_
#include "dawn_native/BlendState.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class BlendState : public BlendStateBase {
public:
BlendState(BlendStateBuilder* builder);
void ApplyNow(uint32_t attachment);
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_BLENDSTATEGL_H_

View File

@@ -0,0 +1,62 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/BufferGL.h"
namespace backend { namespace opengl {
// Buffer
Buffer::Buffer(BufferBuilder* builder) : BufferBase(builder) {
glGenBuffers(1, &mBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW);
}
GLuint Buffer::GetHandle() const {
return mBuffer;
}
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) {
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferSubData(GL_ARRAY_BUFFER, start, count, data);
}
void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
// TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high
// version of OpenGL that would let us map the buffer unsynchronized.
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* data = glMapBufferRange(GL_ARRAY_BUFFER, start, count, GL_MAP_READ_BIT);
CallMapReadCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data);
}
void Buffer::MapWriteAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
// TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high
// version of OpenGL that would let us map the buffer unsynchronized.
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* data = glMapBufferRange(GL_ARRAY_BUFFER, start, count, GL_MAP_WRITE_BIT);
CallMapWriteCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data);
}
void Buffer::UnmapImpl() {
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glUnmapBuffer(GL_ARRAY_BUFFER);
}
// BufferView
BufferView::BufferView(BufferViewBuilder* builder) : BufferViewBase(builder) {
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,48 @@
// Copyright 2017 The Dawn 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_BUFFERGL_H_
#define BACKEND_OPENGL_BUFFERGL_H_
#include "dawn_native/Buffer.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class Device;
class Buffer : public BufferBase {
public:
Buffer(BufferBuilder* builder);
GLuint GetHandle() const;
private:
void SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) override;
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
void MapWriteAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
void UnmapImpl() override;
GLuint mBuffer = 0;
};
class BufferView : public BufferViewBase {
public:
BufferView(BufferViewBuilder* builder);
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_BUFFERGL_H_

View File

@@ -0,0 +1,656 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/CommandBufferGL.h"
#include "dawn_native/BindGroup.h"
#include "dawn_native/Commands.h"
#include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/ComputePipelineGL.h"
#include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/InputStateGL.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
#include "dawn_native/opengl/PipelineLayoutGL.h"
#include "dawn_native/opengl/RenderPipelineGL.h"
#include "dawn_native/opengl/SamplerGL.h"
#include "dawn_native/opengl/TextureGL.h"
#include <cstring>
namespace backend { namespace opengl {
namespace {
GLenum IndexFormatType(dawn::IndexFormat format) {
switch (format) {
case dawn::IndexFormat::Uint16:
return GL_UNSIGNED_SHORT;
case dawn::IndexFormat::Uint32:
return GL_UNSIGNED_INT;
default:
UNREACHABLE();
}
}
GLenum VertexFormatType(dawn::VertexFormat format) {
switch (format) {
case dawn::VertexFormat::FloatR32G32B32A32:
case dawn::VertexFormat::FloatR32G32B32:
case dawn::VertexFormat::FloatR32G32:
case dawn::VertexFormat::FloatR32:
return GL_FLOAT;
case dawn::VertexFormat::IntR32G32B32A32:
case dawn::VertexFormat::IntR32G32B32:
case dawn::VertexFormat::IntR32G32:
case dawn::VertexFormat::IntR32:
return GL_INT;
case dawn::VertexFormat::UshortR16G16B16A16:
case dawn::VertexFormat::UshortR16G16:
return GL_UNSIGNED_SHORT;
case dawn::VertexFormat::UnormR8G8B8A8:
case dawn::VertexFormat::UnormR8G8:
return GL_UNSIGNED_BYTE;
default:
UNREACHABLE();
}
}
GLboolean VertexFormatIsNormalized(dawn::VertexFormat format) {
switch (format) {
case dawn::VertexFormat::UnormR8G8B8A8:
case dawn::VertexFormat::UnormR8G8:
return GL_TRUE;
default:
return GL_FALSE;
}
}
// Push constants are implemented using OpenGL uniforms, however they aren't part of the
// global OpenGL state but are part of the program state instead. This means that we have to
// reapply push constants on pipeline change.
//
// This structure tracks the current values of push constants as well as dirty bits for push
// constants that should be applied before the next draw or dispatch.
class PushConstantTracker {
public:
PushConstantTracker() {
for (auto stage : IterateStages(kAllStages)) {
mValues[stage].fill(0);
// No need to set dirty bits as a pipeline will be set before the next operation
// using push constants.
}
}
void OnSetPushConstants(dawn::ShaderStageBit stages,
uint32_t count,
uint32_t offset,
const uint32_t* data) {
for (auto stage : IterateStages(stages)) {
memcpy(&mValues[stage][offset], data, count * sizeof(uint32_t));
// Use 64 bit masks and make sure there are no shift UB
static_assert(kMaxPushConstants <= 8 * sizeof(unsigned long long) - 1, "");
mDirtyBits[stage] |= ((1ull << count) - 1ull) << offset;
}
}
void OnSetPipeline(PipelineBase* pipeline) {
for (auto stage : IterateStages(kAllStages)) {
mDirtyBits[stage] = pipeline->GetPushConstants(stage).mask;
}
}
void Apply(PipelineBase* pipeline, PipelineGL* glPipeline) {
for (auto stage : IterateStages(kAllStages)) {
const auto& pushConstants = pipeline->GetPushConstants(stage);
const auto& glPushConstants = glPipeline->GetGLPushConstants(stage);
for (uint32_t constant :
IterateBitSet(mDirtyBits[stage] & pushConstants.mask)) {
GLint location = glPushConstants[constant];
switch (pushConstants.types[constant]) {
case PushConstantType::Int:
glUniform1i(location,
*reinterpret_cast<GLint*>(&mValues[stage][constant]));
break;
case PushConstantType::UInt:
glUniform1ui(location,
*reinterpret_cast<GLuint*>(&mValues[stage][constant]));
break;
case PushConstantType::Float:
float value;
// Use a memcpy to avoid strict-aliasing warnings, even if it is
// still technically undefined behavior.
memcpy(&value, &mValues[stage][constant], sizeof(value));
glUniform1f(location, value);
break;
}
}
mDirtyBits[stage].reset();
}
}
private:
PerStage<std::array<uint32_t, kMaxPushConstants>> mValues;
PerStage<std::bitset<kMaxPushConstants>> mDirtyBits;
};
// Vertex buffers and index buffers are implemented as part of an OpenGL VAO that
// corresponds to an InputState. On the contrary in Dawn they are part of the global state.
// This means that we have to re-apply these buffers on an InputState change.
class InputBufferTracker {
public:
void OnSetIndexBuffer(BufferBase* buffer) {
mIndexBufferDirty = true;
mIndexBuffer = ToBackend(buffer);
}
void OnSetVertexBuffers(uint32_t startSlot,
uint32_t count,
Ref<BufferBase>* buffers,
uint32_t* offsets) {
for (uint32_t i = 0; i < count; ++i) {
uint32_t slot = startSlot + i;
mVertexBuffers[slot] = ToBackend(buffers[i].Get());
mVertexBufferOffsets[slot] = offsets[i];
}
// Use 64 bit masks and make sure there are no shift UB
static_assert(kMaxVertexInputs <= 8 * sizeof(unsigned long long) - 1, "");
mDirtyVertexBuffers |= ((1ull << count) - 1ull) << startSlot;
}
void OnSetPipeline(RenderPipelineBase* pipeline) {
InputStateBase* inputState = pipeline->GetInputState();
if (mLastInputState == inputState) {
return;
}
mIndexBufferDirty = true;
mDirtyVertexBuffers |= inputState->GetInputsSetMask();
mLastInputState = ToBackend(inputState);
}
void Apply() {
if (mIndexBufferDirty && mIndexBuffer != nullptr) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetHandle());
mIndexBufferDirty = false;
}
for (uint32_t slot :
IterateBitSet(mDirtyVertexBuffers & mLastInputState->GetInputsSetMask())) {
for (uint32_t location :
IterateBitSet(mLastInputState->GetAttributesUsingInput(slot))) {
auto attribute = mLastInputState->GetAttribute(location);
GLuint buffer = mVertexBuffers[slot]->GetHandle();
uint32_t offset = mVertexBufferOffsets[slot];
auto input = mLastInputState->GetInput(slot);
auto components = VertexFormatNumComponents(attribute.format);
auto formatType = VertexFormatType(attribute.format);
GLboolean normalized = VertexFormatIsNormalized(attribute.format);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(
location, components, formatType, normalized, input.stride,
reinterpret_cast<void*>(
static_cast<intptr_t>(offset + attribute.offset)));
}
}
mDirtyVertexBuffers.reset();
}
private:
bool mIndexBufferDirty = false;
Buffer* mIndexBuffer = nullptr;
std::bitset<kMaxVertexInputs> mDirtyVertexBuffers;
std::array<Buffer*, kMaxVertexInputs> mVertexBuffers;
std::array<uint32_t, kMaxVertexInputs> mVertexBufferOffsets;
InputState* mLastInputState = nullptr;
};
// Handles SetBindGroup commands with the specifics of translating to OpenGL texture and
// buffer units
void ApplyBindGroup(uint32_t index,
BindGroupBase* group,
PipelineLayout* pipelineLayout,
PipelineGL* pipeline) {
const auto& indices = pipelineLayout->GetBindingIndexInfo()[index];
const auto& layout = group->GetLayout()->GetBindingInfo();
for (uint32_t binding : IterateBitSet(layout.mask)) {
switch (layout.types[binding]) {
case dawn::BindingType::UniformBuffer: {
BufferView* view = ToBackend(group->GetBindingAsBufferView(binding));
GLuint buffer = ToBackend(view->GetBuffer())->GetHandle();
GLuint uboIndex = indices[binding];
glBindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, view->GetOffset(),
view->GetSize());
} break;
case dawn::BindingType::Sampler: {
GLuint sampler =
ToBackend(group->GetBindingAsSampler(binding))->GetHandle();
GLuint samplerIndex = indices[binding];
for (auto unit : pipeline->GetTextureUnitsForSampler(samplerIndex)) {
glBindSampler(unit, sampler);
}
} break;
case dawn::BindingType::SampledTexture: {
TextureView* view = ToBackend(group->GetBindingAsTextureView(binding));
Texture* texture = ToBackend(view->GetTexture());
GLuint handle = texture->GetHandle();
GLenum target = texture->GetGLTarget();
GLuint textureIndex = indices[binding];
for (auto unit : pipeline->GetTextureUnitsForTexture(textureIndex)) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(target, handle);
}
} break;
case dawn::BindingType::StorageBuffer: {
BufferView* view = ToBackend(group->GetBindingAsBufferView(binding));
GLuint buffer = ToBackend(view->GetBuffer())->GetHandle();
GLuint ssboIndex = indices[binding];
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer,
view->GetOffset(), view->GetSize());
} break;
}
}
}
} // namespace
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
: CommandBufferBase(builder), mCommands(builder->AcquireCommands()) {
}
CommandBuffer::~CommandBuffer() {
FreeCommands(&mCommands);
}
void CommandBuffer::Execute() {
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
mCommands.NextCommand<BeginComputePassCmd>();
ExecuteComputePass();
} break;
case Command::BeginRenderPass: {
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
ExecuteRenderPass(ToBackend(cmd->info.Get()));
} break;
case Command::CopyBufferToBuffer: {
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
auto& src = copy->source;
auto& dst = copy->destination;
glBindBuffer(GL_PIXEL_PACK_BUFFER, ToBackend(src.buffer)->GetHandle());
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, ToBackend(dst.buffer)->GetHandle());
glCopyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, src.offset,
dst.offset, copy->size);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} break;
case Command::CopyBufferToTexture: {
CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
auto& src = copy->source;
auto& dst = copy->destination;
Buffer* buffer = ToBackend(src.buffer.Get());
Texture* texture = ToBackend(dst.texture.Get());
GLenum target = texture->GetGLTarget();
auto format = texture->GetGLFormat();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle());
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, texture->GetHandle());
ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D);
glPixelStorei(GL_UNPACK_ROW_LENGTH,
copy->rowPitch / TextureFormatPixelSize(texture->GetFormat()));
glTexSubImage2D(target, dst.level, dst.x, dst.y, dst.width, dst.height,
format.format, format.type,
reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} break;
case Command::CopyTextureToBuffer: {
CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>();
auto& src = copy->source;
auto& dst = copy->destination;
Texture* texture = ToBackend(src.texture.Get());
Buffer* buffer = ToBackend(dst.buffer.Get());
auto format = texture->GetGLFormat();
// The only way to move data from a texture to a buffer in GL is via
// glReadPixels with a pack buffer. Create a temporary FBO for the copy.
ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D);
glBindTexture(GL_TEXTURE_2D, texture->GetHandle());
GLuint readFBO = 0;
glGenFramebuffers(1, &readFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
texture->GetHandle(), src.level);
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle());
glPixelStorei(GL_PACK_ROW_LENGTH,
copy->rowPitch / TextureFormatPixelSize(texture->GetFormat()));
ASSERT(src.depth == 1 && src.z == 0);
void* offset = reinterpret_cast<void*>(static_cast<uintptr_t>(dst.offset));
glReadPixels(src.x, src.y, src.width, src.height, format.format, format.type,
offset);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glDeleteFramebuffers(1, &readFBO);
} break;
default: { UNREACHABLE(); } break;
}
}
}
void CommandBuffer::ExecuteComputePass() {
PushConstantTracker pushConstants;
ComputePipeline* lastPipeline = nullptr;
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
return;
} break;
case Command::Dispatch: {
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
pushConstants.Apply(lastPipeline, lastPipeline);
glDispatchCompute(dispatch->x, dispatch->y, dispatch->z);
// TODO(cwallez@chromium.org): add barriers to the API
glMemoryBarrier(GL_ALL_BARRIER_BITS);
} break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
lastPipeline->ApplyNow();
pushConstants.OnSetPipeline(lastPipeline);
} break;
case Command::SetPushConstants: {
SetPushConstantsCmd* cmd = mCommands.NextCommand<SetPushConstantsCmd>();
uint32_t* data = mCommands.NextData<uint32_t>(cmd->count);
pushConstants.OnSetPushConstants(cmd->stages, cmd->count, cmd->offset, data);
} break;
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
ApplyBindGroup(cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline);
} break;
default: { UNREACHABLE(); } break;
}
}
// EndComputePass should have been called
UNREACHABLE();
}
void CommandBuffer::ExecuteRenderPass(RenderPassDescriptorBase* renderPass) {
GLuint fbo = 0;
// Create the framebuffer used for this render pass and calls the correct glDrawBuffers
{
// TODO(kainino@chromium.org): This is added to possibly work around an issue seen on
// Windows/Intel. It should break any feedback loop before the clears, even if there
// shouldn't be any negative effects from this. Investigate whether it's actually
// needed.
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// TODO(kainino@chromium.org): possible future optimization: create these framebuffers
// at Framebuffer build time (or maybe CommandBuffer build time) so they don't have to
// be created and destroyed at draw time.
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
// Mapping from attachmentSlot to GL framebuffer attachment points. Defaults to zero
// (GL_NONE).
std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
// Construct GL framebuffer
unsigned int attachmentCount = 0;
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
TextureViewBase* textureView = renderPass->GetColorAttachment(i).view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
// Attach color buffers.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
texture, 0);
drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
attachmentCount = i + 1;
// TODO(kainino@chromium.org): the color clears (later in
// this function) may be undefined for non-normalized integer formats.
dawn::TextureFormat format = textureView->GetTexture()->GetFormat();
ASSERT(format == dawn::TextureFormat::R8G8B8A8Unorm ||
format == dawn::TextureFormat::R8G8Unorm ||
format == dawn::TextureFormat::R8Unorm ||
format == dawn::TextureFormat::B8G8R8A8Unorm);
}
glDrawBuffers(attachmentCount, drawBuffers.data());
if (renderPass->HasDepthStencilAttachment()) {
TextureViewBase* textureView = renderPass->GetDepthStencilAttachment().view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
dawn::TextureFormat format = textureView->GetTexture()->GetFormat();
// Attach depth/stencil buffer.
GLenum glAttachment = 0;
// TODO(kainino@chromium.org): it may be valid to just always use
// GL_DEPTH_STENCIL_ATTACHMENT here.
if (TextureFormatHasDepth(format)) {
if (TextureFormatHasStencil(format)) {
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else {
glAttachment = GL_DEPTH_ATTACHMENT;
}
} else {
glAttachment = GL_STENCIL_ATTACHMENT;
}
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, GL_TEXTURE_2D, texture,
0);
// TODO(kainino@chromium.org): the depth/stencil clears (later in
// this function) may be undefined for other texture formats.
ASSERT(format == dawn::TextureFormat::D32FloatS8Uint);
}
}
// Clear framebuffer attachments as needed
{
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
const auto& attachmentInfo = renderPass->GetColorAttachment(i);
// Load op - color
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
}
}
if (renderPass->HasDepthStencilAttachment()) {
const auto& attachmentInfo = renderPass->GetDepthStencilAttachment();
dawn::TextureFormat attachmentFormat =
attachmentInfo.view->GetTexture()->GetFormat();
// Load op - depth/stencil
bool doDepthClear = TextureFormatHasDepth(attachmentFormat) &&
(attachmentInfo.depthLoadOp == dawn::LoadOp::Clear);
bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
(attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear);
if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
attachmentInfo.clearStencil);
} else if (doDepthClear) {
glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
} else if (doStencilClear) {
const GLint clearStencil = attachmentInfo.clearStencil;
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
}
}
}
RenderPipeline* lastPipeline = nullptr;
uint32_t indexBufferBaseOffset = 0;
PersistentPipelineState persistentPipelineState;
PushConstantTracker pushConstants;
InputBufferTracker inputBuffers;
// Set defaults for dynamic state
persistentPipelineState.SetDefaultState();
glBlendColor(0, 0, 0, 0);
glViewport(0, 0, renderPass->GetWidth(), renderPass->GetHeight());
glScissor(0, 0, renderPass->GetWidth(), renderPass->GetHeight());
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
glDeleteFramebuffers(1, &fbo);
return;
} break;
case Command::DrawArrays: {
DrawArraysCmd* draw = mCommands.NextCommand<DrawArraysCmd>();
pushConstants.Apply(lastPipeline, lastPipeline);
inputBuffers.Apply();
if (draw->firstInstance > 0) {
glDrawArraysInstancedBaseInstance(lastPipeline->GetGLPrimitiveTopology(),
draw->firstVertex, draw->vertexCount,
draw->instanceCount, draw->firstInstance);
} else {
// This branch is only needed on OpenGL < 4.2
glDrawArraysInstanced(lastPipeline->GetGLPrimitiveTopology(),
draw->firstVertex, draw->vertexCount,
draw->instanceCount);
}
} break;
case Command::DrawElements: {
DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
pushConstants.Apply(lastPipeline, lastPipeline);
inputBuffers.Apply();
dawn::IndexFormat indexFormat = lastPipeline->GetIndexFormat();
size_t formatSize = IndexFormatSize(indexFormat);
GLenum formatType = IndexFormatType(indexFormat);
if (draw->firstInstance > 0) {
glDrawElementsInstancedBaseInstance(
lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType,
reinterpret_cast<void*>(draw->firstIndex * formatSize +
indexBufferBaseOffset),
draw->instanceCount, draw->firstInstance);
} else {
// This branch is only needed on OpenGL < 4.2
glDrawElementsInstanced(
lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType,
reinterpret_cast<void*>(draw->firstIndex * formatSize +
indexBufferBaseOffset),
draw->instanceCount);
}
} break;
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
lastPipeline->ApplyNow(persistentPipelineState);
pushConstants.OnSetPipeline(lastPipeline);
inputBuffers.OnSetPipeline(lastPipeline);
} break;
case Command::SetPushConstants: {
SetPushConstantsCmd* cmd = mCommands.NextCommand<SetPushConstantsCmd>();
uint32_t* data = mCommands.NextData<uint32_t>(cmd->count);
pushConstants.OnSetPushConstants(cmd->stages, cmd->count, cmd->offset, data);
} break;
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
persistentPipelineState.SetStencilReference(cmd->reference);
} break;
case Command::SetScissorRect: {
SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
glScissor(cmd->x, cmd->y, cmd->width, cmd->height);
} break;
case Command::SetBlendColor: {
SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
glBlendColor(cmd->r, cmd->g, cmd->b, cmd->a);
} break;
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
ApplyBindGroup(cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline);
} break;
case Command::SetIndexBuffer: {
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
indexBufferBaseOffset = cmd->offset;
inputBuffers.OnSetIndexBuffer(cmd->buffer.Get());
} break;
case Command::SetVertexBuffers: {
SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
auto offsets = mCommands.NextData<uint32_t>(cmd->count);
inputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, offsets);
} break;
default: { UNREACHABLE(); } break;
}
}
// EndRenderPass should have been called
UNREACHABLE();
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,45 @@
// Copyright 2017 The Dawn 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_COMMANDBUFFERGL_H_
#define BACKEND_OPENGL_COMMANDBUFFERGL_H_
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/CommandBuffer.h"
namespace backend {
class RenderPassDescriptorBase;
} // namespace backend
namespace backend { namespace opengl {
class Device;
class CommandBuffer : public CommandBufferBase {
public:
CommandBuffer(CommandBufferBuilder* builder);
~CommandBuffer();
void Execute();
private:
void ExecuteComputePass();
void ExecuteRenderPass(RenderPassDescriptorBase* renderPass);
CommandIterator mCommands;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_COMMANDBUFFERGL_H_

View File

@@ -0,0 +1,27 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/ComputePipelineGL.h"
namespace backend { namespace opengl {
ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder)
: ComputePipelineBase(builder), PipelineGL(this, builder) {
}
void ComputePipeline::ApplyNow() {
PipelineGL::ApplyNow();
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,35 @@
// Copyright 2017 The Dawn 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_COMPUTEPIPELINEGL_H_
#define BACKEND_OPENGL_COMPUTEPIPELINEGL_H_
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/opengl/PipelineGL.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class ComputePipeline : public ComputePipelineBase, public PipelineGL {
public:
ComputePipeline(ComputePipelineBuilder* builder);
void ApplyNow();
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_COMPUTEPIPELINEGL_H_

View File

@@ -0,0 +1,116 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/DepthStencilStateGL.h"
#include "common/Assert.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
namespace backend { namespace opengl {
namespace {
GLuint OpenGLCompareFunction(dawn::CompareFunction compareFunction) {
switch (compareFunction) {
case dawn::CompareFunction::Never:
return GL_NEVER;
case dawn::CompareFunction::Less:
return GL_LESS;
case dawn::CompareFunction::LessEqual:
return GL_LEQUAL;
case dawn::CompareFunction::Greater:
return GL_GREATER;
case dawn::CompareFunction::GreaterEqual:
return GL_GEQUAL;
case dawn::CompareFunction::NotEqual:
return GL_NOTEQUAL;
case dawn::CompareFunction::Equal:
return GL_EQUAL;
case dawn::CompareFunction::Always:
return GL_ALWAYS;
default:
UNREACHABLE();
}
}
GLuint OpenGLStencilOperation(dawn::StencilOperation stencilOperation) {
switch (stencilOperation) {
case dawn::StencilOperation::Keep:
return GL_KEEP;
case dawn::StencilOperation::Zero:
return GL_ZERO;
case dawn::StencilOperation::Replace:
return GL_REPLACE;
case dawn::StencilOperation::Invert:
return GL_INVERT;
case dawn::StencilOperation::IncrementClamp:
return GL_INCR;
case dawn::StencilOperation::DecrementClamp:
return GL_DECR;
case dawn::StencilOperation::IncrementWrap:
return GL_INCR_WRAP;
case dawn::StencilOperation::DecrementWrap:
return GL_DECR_WRAP;
default:
UNREACHABLE();
}
}
} // namespace
DepthStencilState::DepthStencilState(DepthStencilStateBuilder* builder)
: DepthStencilStateBase(builder) {
}
void DepthStencilState::ApplyNow(PersistentPipelineState& persistentPipelineState) const {
auto& depthInfo = GetDepth();
// Depth writes only occur if depth is enabled
if (depthInfo.compareFunction == dawn::CompareFunction::Always &&
!depthInfo.depthWriteEnabled) {
glDisable(GL_DEPTH_TEST);
} else {
glEnable(GL_DEPTH_TEST);
}
if (depthInfo.depthWriteEnabled) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
glDepthFunc(OpenGLCompareFunction(depthInfo.compareFunction));
if (StencilTestEnabled()) {
glEnable(GL_STENCIL_TEST);
} else {
glDisable(GL_STENCIL_TEST);
}
auto& stencilInfo = GetStencil();
GLenum backCompareFunction = OpenGLCompareFunction(stencilInfo.back.compareFunction);
GLenum frontCompareFunction = OpenGLCompareFunction(stencilInfo.front.compareFunction);
persistentPipelineState.SetStencilFuncsAndMask(backCompareFunction, frontCompareFunction,
stencilInfo.readMask);
glStencilOpSeparate(GL_BACK, OpenGLStencilOperation(stencilInfo.back.stencilFail),
OpenGLStencilOperation(stencilInfo.back.depthFail),
OpenGLStencilOperation(stencilInfo.back.depthStencilPass));
glStencilOpSeparate(GL_FRONT, OpenGLStencilOperation(stencilInfo.front.stencilFail),
OpenGLStencilOperation(stencilInfo.front.depthFail),
OpenGLStencilOperation(stencilInfo.front.depthStencilPass));
glStencilMask(stencilInfo.writeMask);
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,34 @@
// Copyright 2017 The Dawn 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_DEPTHSTENCILSTATEGL_H_
#define BACKEND_OPENGL_DEPTHSTENCILSTATEGL_H_
#include "dawn_native/DepthStencilState.h"
namespace backend { namespace opengl {
class Device;
class PersistentPipelineState;
class DepthStencilState : public DepthStencilStateBase {
public:
DepthStencilState(DepthStencilStateBuilder* builder);
void ApplyNow(PersistentPipelineState& persistentPipelineState) const;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_DEPTHSTENCILSTATEGL_H_

View File

@@ -0,0 +1,115 @@
// Copyright 2018 The Dawn 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 "dawn_native/opengl/DeviceGL.h"
#include "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/RenderPassDescriptor.h"
#include "dawn_native/opengl/BlendStateGL.h"
#include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/CommandBufferGL.h"
#include "dawn_native/opengl/ComputePipelineGL.h"
#include "dawn_native/opengl/DepthStencilStateGL.h"
#include "dawn_native/opengl/InputStateGL.h"
#include "dawn_native/opengl/PipelineLayoutGL.h"
#include "dawn_native/opengl/QueueGL.h"
#include "dawn_native/opengl/RenderPipelineGL.h"
#include "dawn_native/opengl/SamplerGL.h"
#include "dawn_native/opengl/ShaderModuleGL.h"
#include "dawn_native/opengl/SwapChainGL.h"
#include "dawn_native/opengl/TextureGL.h"
namespace backend { namespace opengl {
dawnProcTable GetNonValidatingProcs();
dawnProcTable GetValidatingProcs();
void Init(void* (*getProc)(const char*), dawnProcTable* procs, dawnDevice* device) {
*device = nullptr;
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(getProc));
*procs = GetValidatingProcs();
*device = reinterpret_cast<dawnDevice>(new Device);
glEnable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
}
// Device
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(builder);
}
ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
const dawn::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
}
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder);
}
BufferBase* Device::CreateBuffer(BufferBuilder* builder) {
return new Buffer(builder);
}
BufferViewBase* Device::CreateBufferView(BufferViewBuilder* builder) {
return new BufferView(builder);
}
CommandBufferBase* Device::CreateCommandBuffer(CommandBufferBuilder* builder) {
return new CommandBuffer(builder);
}
ComputePipelineBase* Device::CreateComputePipeline(ComputePipelineBuilder* builder) {
return new ComputePipeline(builder);
}
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
const dawn::PipelineLayoutDescriptor* descriptor) {
return new PipelineLayout(this, descriptor);
}
ResultOrError<QueueBase*> Device::CreateQueueImpl() {
return new Queue(this);
}
RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) {
return new RenderPassDescriptor(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
}
ResultOrError<SamplerBase*> Device::CreateSamplerImpl(
const dawn::SamplerDescriptor* descriptor) {
return new Sampler(this, descriptor);
}
ShaderModuleBase* Device::CreateShaderModule(ShaderModuleBuilder* builder) {
return new ShaderModule(builder);
}
SwapChainBase* Device::CreateSwapChain(SwapChainBuilder* builder) {
return new SwapChain(builder);
}
TextureBase* Device::CreateTexture(TextureBuilder* builder) {
return new Texture(builder);
}
TextureViewBase* Device::CreateTextureView(TextureViewBuilder* builder) {
return new TextureView(builder);
}
void Device::TickImpl() {
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,65 @@
// Copyright 2018 The Dawn 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_DEVICEGL_H_
#define BACKEND_OPENGL_DEVICEGL_H_
#include "dawn/dawncpp.h"
#include "common/Platform.h"
#include "dawn_native/Device.h"
#include "dawn_native/opengl/Forward.h"
#include "glad/glad.h"
// Remove windows.h macros after glad's include of windows.h
#if defined(DAWN_PLATFORM_WINDOWS)
# include "common/windows_with_undefs.h"
#endif
namespace backend { namespace opengl {
class Device : public DeviceBase {
public:
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
TextureBase* CreateTexture(TextureBuilder* builder) override;
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
void TickImpl() override;
private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const dawn::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const dawn::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const dawn::SamplerDescriptor* descriptor) override;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_DEVICEGL_H_

View File

@@ -0,0 +1,78 @@
// Copyright 2018 The Dawn 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_FORWARD_H_
#define BACKEND_OPENGL_FORWARD_H_
#include "dawn_native/ToBackend.h"
namespace {
class BindGroupBase;
class BindGroup;
class RenderPassDescriptor;
} // namespace
namespace backend { namespace opengl {
using BindGroup = BindGroupBase;
using BindGroupLayout = BindGroupLayoutBase;
class BlendState;
class Buffer;
class BufferView;
class CommandBuffer;
class ComputePipeline;
class DepthStencilState;
class Device;
class InputState;
class PersistentPipelineState;
class PipelineLayout;
class Queue;
using RenderPassDescriptor = RenderPassDescriptorBase;
class RenderPipeline;
class Sampler;
class ShaderModule;
class SwapChain;
class Texture;
class TextureView;
struct OpenGLBackendTraits {
using BindGroupType = BindGroup;
using BindGroupLayoutType = BindGroupLayout;
using BlendStateType = BlendState;
using BufferType = Buffer;
using BufferViewType = BufferView;
using CommandBufferType = CommandBuffer;
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
using RenderPassDescriptorType = RenderPassDescriptor;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
using SwapChainType = SwapChain;
using TextureType = Texture;
using TextureViewType = TextureView;
};
template <typename T>
auto ToBackend(T&& common) -> decltype(ToBackendBase<OpenGLBackendTraits>(common)) {
return ToBackendBase<OpenGLBackendTraits>(common);
}
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_FORWARD_H_

View File

@@ -0,0 +1,32 @@
// Copyright 2017 The Dawn 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 "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/RenderPassDescriptor.h"
#include "dawn_native/opengl/BlendStateGL.h"
#include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/CommandBufferGL.h"
#include "dawn_native/opengl/ComputePipelineGL.h"
#include "dawn_native/opengl/DepthStencilStateGL.h"
#include "dawn_native/opengl/DeviceGL.h"
#include "dawn_native/opengl/InputStateGL.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
#include "dawn_native/opengl/PipelineLayoutGL.h"
#include "dawn_native/opengl/QueueGL.h"
#include "dawn_native/opengl/RenderPipelineGL.h"
#include "dawn_native/opengl/SamplerGL.h"
#include "dawn_native/opengl/ShaderModuleGL.h"
#include "dawn_native/opengl/SwapChainGL.h"
#include "dawn_native/opengl/TextureGL.h"

View File

@@ -0,0 +1,61 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/InputStateGL.h"
#include "common/Assert.h"
namespace backend { namespace opengl {
InputState::InputState(InputStateBuilder* builder) : InputStateBase(builder) {
glGenVertexArrays(1, &mVertexArrayObject);
glBindVertexArray(mVertexArrayObject);
auto& attributesSetMask = GetAttributesSetMask();
for (uint32_t location = 0; location < attributesSetMask.size(); ++location) {
if (!attributesSetMask[location]) {
continue;
}
auto attribute = GetAttribute(location);
glEnableVertexAttribArray(location);
attributesUsingInput[attribute.bindingSlot][location] = true;
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 dawn::InputStepMode::Vertex:
break;
case dawn::InputStepMode::Instance:
glVertexAttribDivisor(location, 1);
break;
default:
UNREACHABLE();
}
}
}
}
std::bitset<kMaxVertexAttributes> InputState::GetAttributesUsingInput(uint32_t slot) const {
return attributesUsingInput[slot];
}
GLuint InputState::GetVAO() {
return mVertexArrayObject;
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,40 @@
// Copyright 2017 The Dawn 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_INPUTSTATEGL_H_
#define BACKEND_OPENGL_INPUTSTATEGL_H_
#include "dawn_native/InputState.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class Device;
class InputState : public InputStateBase {
public:
InputState(InputStateBuilder* builder);
std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const;
GLuint GetVAO();
private:
GLuint mVertexArrayObject;
std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexInputs> attributesUsingInput;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_INPUTSTATEGL_H_

View File

@@ -0,0 +1,54 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/PersistentPipelineStateGL.h"
namespace backend { namespace opengl {
void PersistentPipelineState::SetDefaultState() {
CallGLStencilFunc();
}
void PersistentPipelineState::SetStencilFuncsAndMask(GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask) {
if (mStencilBackCompareFunction == stencilBackCompareFunction &&
mStencilFrontCompareFunction == stencilFrontCompareFunction &&
mStencilReadMask == stencilReadMask) {
return;
}
mStencilBackCompareFunction = stencilBackCompareFunction;
mStencilFrontCompareFunction = stencilFrontCompareFunction;
mStencilReadMask = stencilReadMask;
CallGLStencilFunc();
}
void PersistentPipelineState::SetStencilReference(uint32_t stencilReference) {
if (mStencilReference == stencilReference) {
return;
}
mStencilReference = stencilReference;
CallGLStencilFunc();
}
void PersistentPipelineState::CallGLStencilFunc() {
glStencilFuncSeparate(GL_BACK, mStencilBackCompareFunction, mStencilReference,
mStencilReadMask);
glStencilFuncSeparate(GL_FRONT, mStencilFrontCompareFunction, mStencilReference,
mStencilReadMask);
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,43 @@
// Copyright 2017 The Dawn 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_PERSISTENTPIPELINESTATEGL_H_
#define BACKEND_OPENGL_PERSISTENTPIPELINESTATEGL_H_
#include "dawn/dawncpp.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class PersistentPipelineState {
public:
void SetDefaultState();
void SetStencilFuncsAndMask(GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask);
void SetStencilReference(uint32_t stencilReference);
private:
void CallGLStencilFunc();
GLenum mStencilBackCompareFunction = GL_ALWAYS;
GLenum mStencilFrontCompareFunction = GL_ALWAYS;
GLuint mStencilReadMask = 0xffffffff;
GLuint mStencilReference = 0;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_PERSISTENTPIPELINESTATEGL_H_

View File

@@ -0,0 +1,215 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/PipelineGL.h"
#include "common/BitSetIterator.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
#include "dawn_native/opengl/PipelineLayoutGL.h"
#include "dawn_native/opengl/ShaderModuleGL.h"
#include <iostream>
#include <set>
namespace backend { namespace opengl {
namespace {
GLenum GLShaderType(dawn::ShaderStage stage) {
switch (stage) {
case dawn::ShaderStage::Vertex:
return GL_VERTEX_SHADER;
case dawn::ShaderStage::Fragment:
return GL_FRAGMENT_SHADER;
case dawn::ShaderStage::Compute:
return GL_COMPUTE_SHADER;
default:
UNREACHABLE();
}
}
} // namespace
PipelineGL::PipelineGL(PipelineBase* parent, PipelineBuilder* builder) {
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;
}
};
mProgram = glCreateProgram();
for (auto stage : IterateStages(parent->GetStageMask())) {
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
GLuint shader = CreateShader(GLShaderType(stage), module->GetSource());
glAttachShader(mProgram, shader);
}
glLinkProgram(mProgram);
GLint linkStatus = GL_FALSE;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
GLint infoLogLength = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) {
std::vector<char> buffer(infoLogLength);
glGetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]);
std::cout << "Program link failed:\n";
std::cout << buffer.data() << std::endl;
}
}
for (auto stage : IterateStages(parent->GetStageMask())) {
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
FillPushConstants(module, &mGlPushConstants[stage], mProgram);
}
glUseProgram(mProgram);
// The uniforms are part of the program state so we can pre-bind buffer units, texture units
// etc.
const auto& layout = ToBackend(parent->GetLayout());
const auto& indices = layout->GetBindingIndexInfo();
for (uint32_t group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
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 dawn::BindingType::UniformBuffer: {
GLint location = glGetUniformBlockIndex(mProgram, name.c_str());
glUniformBlockBinding(mProgram, location, indices[group][binding]);
} break;
case dawn::BindingType::StorageBuffer: {
GLuint location = glGetProgramResourceIndex(
mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str());
glShaderStorageBlockBinding(mProgram, location, indices[group][binding]);
} break;
case dawn::BindingType::Sampler:
case dawn::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(parent->GetStageMask())) {
const auto& module = ToBackend(builder->GetStageInfo(stage).module);
for (const auto& combined : module->GetCombinedSamplerInfo()) {
combinedSamplersSet.insert(combined);
}
}
mUnitsForSamplers.resize(layout->GetNumSamplers());
mUnitsForTextures.resize(layout->GetNumSampledTextures());
GLuint textureUnit = layout->GetTextureUnitsUsed();
for (const auto& combined : combinedSamplersSet) {
std::string name = combined.GetName();
GLint location = glGetUniformLocation(mProgram, name.c_str());
glUniform1i(location, textureUnit);
GLuint samplerIndex =
indices[combined.samplerLocation.group][combined.samplerLocation.binding];
mUnitsForSamplers[samplerIndex].push_back(textureUnit);
GLuint textureIndex =
indices[combined.textureLocation.group][combined.textureLocation.binding];
mUnitsForTextures[textureIndex].push_back(textureUnit);
textureUnit++;
}
}
}
const PipelineGL::GLPushConstantInfo& PipelineGL::GetGLPushConstants(
dawn::ShaderStage stage) const {
return mGlPushConstants[stage];
}
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForSampler(GLuint index) const {
ASSERT(index < mUnitsForSamplers.size());
return mUnitsForSamplers[index];
}
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTexture(GLuint index) const {
ASSERT(index < mUnitsForSamplers.size());
return mUnitsForTextures[index];
}
GLuint PipelineGL::GetProgramHandle() const {
return mProgram;
}
void PipelineGL::ApplyNow() {
glUseProgram(mProgram);
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,54 @@
// Copyright 2017 The Dawn 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 "dawn_native/Pipeline.h"
#include "glad/glad.h"
#include <vector>
namespace backend { namespace opengl {
class Device;
class PersistentPipelineState;
class ShaderModule;
class PipelineGL {
public:
PipelineGL(PipelineBase* parent, PipelineBuilder* builder);
using GLPushConstantInfo = std::array<GLint, kMaxPushConstants>;
using BindingLocations =
std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>;
const GLPushConstantInfo& GetGLPushConstants(dawn::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 mProgram;
PerStage<GLPushConstantInfo> mGlPushConstants;
std::vector<std::vector<GLuint>> mUnitsForSamplers;
std::vector<std::vector<GLuint>> mUnitsForTextures;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_PIPELINEGL_H_

View File

@@ -0,0 +1,80 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/PipelineLayoutGL.h"
#include "common/BitSetIterator.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/opengl/DeviceGL.h"
namespace backend { namespace opengl {
PipelineLayout::PipelineLayout(Device* device, const dawn::PipelineLayoutDescriptor* descriptor)
: PipelineLayoutBase(device, descriptor) {
GLuint uboIndex = 0;
GLuint samplerIndex = 0;
GLuint sampledTextureIndex = 0;
GLuint ssboIndex = 0;
for (uint32_t group : IterateBitSet(GetBindGroupLayoutsMask())) {
const auto& groupInfo = GetBindGroupLayout(group)->GetBindingInfo();
for (size_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
if (!groupInfo.mask[binding]) {
continue;
}
switch (groupInfo.types[binding]) {
case dawn::BindingType::UniformBuffer:
mIndexInfo[group][binding] = uboIndex;
uboIndex++;
break;
case dawn::BindingType::Sampler:
mIndexInfo[group][binding] = samplerIndex;
samplerIndex++;
break;
case dawn::BindingType::SampledTexture:
mIndexInfo[group][binding] = sampledTextureIndex;
sampledTextureIndex++;
break;
case dawn::BindingType::StorageBuffer:
mIndexInfo[group][binding] = ssboIndex;
ssboIndex++;
break;
}
}
}
mNumSamplers = samplerIndex;
mNumSampledTextures = sampledTextureIndex;
}
const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo() const {
return mIndexInfo;
}
GLuint PipelineLayout::GetTextureUnitsUsed() const {
return 0;
}
size_t PipelineLayout::GetNumSamplers() const {
return mNumSamplers;
}
size_t PipelineLayout::GetNumSampledTextures() const {
return mNumSampledTextures;
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,46 @@
// Copyright 2017 The Dawn 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 "dawn_native/PipelineLayout.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class Device;
class PipelineLayout : public PipelineLayoutBase {
public:
PipelineLayout(Device* device, const dawn::PipelineLayoutDescriptor* descriptor);
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:
BindingIndexInfo mIndexInfo;
size_t mNumSamplers;
size_t mNumSampledTextures;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_PIPELINELAYOUTGL_H_

View File

@@ -0,0 +1,31 @@
// Copyright 2018 The Dawn 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 "dawn_native/opengl/QueueGL.h"
#include "dawn_native/opengl/CommandBufferGL.h"
#include "dawn_native/opengl/DeviceGL.h"
namespace backend { namespace opengl {
Queue::Queue(Device* device) : QueueBase(device) {
}
void Queue::Submit(uint32_t numCommands, CommandBuffer* const* commands) {
for (uint32_t i = 0; i < numCommands; ++i) {
commands[i]->Execute();
}
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,35 @@
// Copyright 2018 The Dawn 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_QUEUEGL_H_
#define BACKEND_OPENGL_QUEUEGL_H_
#include "dawn_native/Queue.h"
namespace backend { namespace opengl {
class CommandBuffer;
class Device;
class Queue : public QueueBase {
public:
Queue(Device* device);
// Dawn API
void Submit(uint32_t numCommands, CommandBuffer* const* commands);
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_QUEUEGL_H_

View File

@@ -0,0 +1,68 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/RenderPipelineGL.h"
#include "dawn_native/opengl/BlendStateGL.h"
#include "dawn_native/opengl/DepthStencilStateGL.h"
#include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/InputStateGL.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
namespace backend { namespace opengl {
namespace {
GLenum GLPrimitiveTopology(dawn::PrimitiveTopology primitiveTopology) {
switch (primitiveTopology) {
case dawn::PrimitiveTopology::PointList:
return GL_POINTS;
case dawn::PrimitiveTopology::LineList:
return GL_LINES;
case dawn::PrimitiveTopology::LineStrip:
return GL_LINE_STRIP;
case dawn::PrimitiveTopology::TriangleList:
return GL_TRIANGLES;
case dawn::PrimitiveTopology::TriangleStrip:
return GL_TRIANGLE_STRIP;
default:
UNREACHABLE();
}
}
} // namespace
RenderPipeline::RenderPipeline(RenderPipelineBuilder* builder)
: RenderPipelineBase(builder),
PipelineGL(this, builder),
mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {
}
GLenum RenderPipeline::GetGLPrimitiveTopology() const {
return mGlPrimitiveTopology;
}
void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
PipelineGL::ApplyNow();
auto inputState = ToBackend(GetInputState());
glBindVertexArray(inputState->GetVAO());
auto depthStencilState = ToBackend(GetDepthStencilState());
depthStencilState->ApplyNow(persistentPipelineState);
for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
}
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,44 @@
// Copyright 2017 The Dawn 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_RENDERPIPELINEGL_H_
#define BACKEND_OPENGL_RENDERPIPELINEGL_H_
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/opengl/PipelineGL.h"
#include "glad/glad.h"
#include <vector>
namespace backend { namespace opengl {
class PersistentPipelineState;
class RenderPipeline : public RenderPipelineBase, public PipelineGL {
public:
RenderPipeline(RenderPipelineBuilder* builder);
GLenum GetGLPrimitiveTopology() const;
void ApplyNow(PersistentPipelineState& persistentPipelineState);
private:
GLenum mGlPrimitiveTopology;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_RENDERPIPELINEGL_H_

View File

@@ -0,0 +1,89 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/SamplerGL.h"
#include "common/Assert.h"
#include "dawn_native/opengl/DeviceGL.h"
namespace backend { namespace opengl {
namespace {
GLenum MagFilterMode(dawn::FilterMode filter) {
switch (filter) {
case dawn::FilterMode::Nearest:
return GL_NEAREST;
case dawn::FilterMode::Linear:
return GL_LINEAR;
default:
UNREACHABLE();
}
}
GLenum MinFilterMode(dawn::FilterMode minFilter, dawn::FilterMode mipMapFilter) {
switch (minFilter) {
case dawn::FilterMode::Nearest:
switch (mipMapFilter) {
case dawn::FilterMode::Nearest:
return GL_NEAREST_MIPMAP_NEAREST;
case dawn::FilterMode::Linear:
return GL_NEAREST_MIPMAP_LINEAR;
default:
UNREACHABLE();
}
case dawn::FilterMode::Linear:
switch (mipMapFilter) {
case dawn::FilterMode::Nearest:
return GL_LINEAR_MIPMAP_NEAREST;
case dawn::FilterMode::Linear:
return GL_LINEAR_MIPMAP_LINEAR;
default:
UNREACHABLE();
}
default:
UNREACHABLE();
}
}
GLenum WrapMode(dawn::AddressMode mode) {
switch (mode) {
case dawn::AddressMode::Repeat:
return GL_REPEAT;
case dawn::AddressMode::MirroredRepeat:
return GL_MIRRORED_REPEAT;
case dawn::AddressMode::ClampToEdge:
return GL_CLAMP_TO_EDGE;
default:
UNREACHABLE();
}
}
} // namespace
Sampler::Sampler(Device* device, const dawn::SamplerDescriptor* descriptor)
: SamplerBase(device, descriptor) {
glGenSamplers(1, &mHandle);
glSamplerParameteri(mHandle, GL_TEXTURE_MAG_FILTER, MagFilterMode(descriptor->magFilter));
glSamplerParameteri(mHandle, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
}
GLuint Sampler::GetHandle() const {
return mHandle;
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,38 @@
// Copyright 2017 The Dawn 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 "dawn_native/Sampler.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class Device;
class Sampler : public SamplerBase {
public:
Sampler(Device* device, const dawn::SamplerDescriptor* descriptor);
GLuint GetHandle() const;
private:
GLuint mHandle;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_SAMPLERGL_H_

View File

@@ -0,0 +1,132 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/ShaderModuleGL.h"
#include "common/Assert.h"
#include "common/Platform.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 << "dawn_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 << "dawn_combined";
o << "_" << samplerLocation.group << "_" << samplerLocation.binding;
o << "_with_" << textureLocation.group << "_" << textureLocation.binding;
return o.str();
}
ShaderModule::ShaderModule(ShaderModuleBuilder* builder) : ShaderModuleBase(builder) {
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(DAWN_PLATFORM_APPLE)
options.version = 410;
#else
options.version = 440;
#endif
compiler.set_options(options);
// Rename the push constant block to be prefixed with the shader stage type so that uniform
// names don't match between the FS and the VS.
const auto& resources = compiler.get_shader_resources();
if (resources.push_constant_buffers.size() > 0) {
const char* prefix = nullptr;
switch (compiler.get_execution_model()) {
case spv::ExecutionModelVertex:
prefix = "vs_";
break;
case spv::ExecutionModelFragment:
prefix = "fs_";
break;
case spv::ExecutionModelGLCompute:
prefix = "cs_";
break;
default:
UNREACHABLE();
}
auto interfaceBlock = resources.push_constant_buffers[0];
compiler.set_name(interfaceBlock.id, prefix + interfaceBlock.name);
}
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()) {
mCombinedInfo.emplace_back();
auto& info = mCombinedInfo.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 "dawn_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);
}
}
}
mGlslSource = compiler.compile();
}
const char* ShaderModule::GetSource() const {
return reinterpret_cast<const char*>(mGlslSource.data());
}
const ShaderModule::CombinedSamplerInfo& ShaderModule::GetCombinedSamplerInfo() const {
return mCombinedInfo;
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,57 @@
// Copyright 2017 The Dawn 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 "dawn_native/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(ShaderModuleBuilder* builder);
using CombinedSamplerInfo = std::vector<CombinedSampler>;
const char* GetSource() const;
const CombinedSamplerInfo& GetCombinedSamplerInfo() const;
private:
CombinedSamplerInfo mCombinedInfo;
std::string mGlslSource;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_SHADERMODULEGL_H_

View File

@@ -0,0 +1,47 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/SwapChainGL.h"
#include "dawn_native/Device.h"
#include "dawn_native/opengl/TextureGL.h"
#include <dawn/dawn_wsi.h>
namespace backend { namespace opengl {
SwapChain::SwapChain(SwapChainBuilder* builder) : SwapChainBase(builder) {
const auto& im = GetImplementation();
im.Init(im.userData, nullptr);
}
SwapChain::~SwapChain() {
}
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
const auto& im = GetImplementation();
dawnSwapChainNextTexture next = {};
dawnSwapChainError error = im.GetNextTexture(im.userData, &next);
if (error) {
GetDevice()->HandleError(error);
return nullptr;
}
GLuint nativeTexture = next.texture.u32;
return new Texture(builder, nativeTexture);
}
void SwapChain::OnBeforePresent(TextureBase*) {
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,38 @@
// Copyright 2017 The Dawn 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_SWAPCHAINGL_H_
#define BACKEND_OPENGL_SWAPCHAINGL_H_
#include "dawn_native/SwapChain.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
class Device;
class SwapChain : public SwapChainBase {
public:
SwapChain(SwapChainBuilder* builder);
~SwapChain();
protected:
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
void OnBeforePresent(TextureBase* texture) override;
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_SWAPCHAINGL_H_

View File

@@ -0,0 +1,119 @@
// Copyright 2017 The Dawn 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 "dawn_native/opengl/TextureGL.h"
#include "common/Assert.h"
#include <algorithm>
#include <vector>
namespace backend { namespace opengl {
namespace {
GLenum TargetForDimension(dawn::TextureDimension dimension) {
switch (dimension) {
case dawn::TextureDimension::e2D:
return GL_TEXTURE_2D;
default:
UNREACHABLE();
}
}
TextureFormatInfo GetGLFormatInfo(dawn::TextureFormat format) {
switch (format) {
case dawn::TextureFormat::R8G8B8A8Unorm:
return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
case dawn::TextureFormat::R8G8Unorm:
return {GL_RG8, GL_RG, GL_UNSIGNED_BYTE};
case dawn::TextureFormat::R8Unorm:
return {GL_R8, GL_RED, GL_UNSIGNED_BYTE};
case dawn::TextureFormat::R8G8B8A8Uint:
return {GL_RGBA8UI, GL_RGBA, GL_UNSIGNED_INT};
case dawn::TextureFormat::R8G8Uint:
return {GL_RG8UI, GL_RG, GL_UNSIGNED_INT};
case dawn::TextureFormat::R8Uint:
return {GL_R8UI, GL_RED, GL_UNSIGNED_INT};
case dawn::TextureFormat::B8G8R8A8Unorm:
// This doesn't have an enum for the internal format in OpenGL, so use RGBA8.
return {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE};
case dawn::TextureFormat::D32FloatS8Uint:
return {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
GL_FLOAT_32_UNSIGNED_INT_24_8_REV};
default:
UNREACHABLE();
}
}
GLuint GenTexture() {
GLuint handle = 0;
glGenTextures(1, &handle);
return handle;
}
} // namespace
// Texture
Texture::Texture(TextureBuilder* builder) : Texture(builder, GenTexture()) {
}
Texture::Texture(TextureBuilder* builder, GLuint handle)
: TextureBase(builder), mHandle(handle) {
mTarget = TargetForDimension(GetDimension());
uint32_t width = GetWidth();
uint32_t height = GetHeight();
uint32_t levels = GetNumMipLevels();
auto formatInfo = GetGLFormatInfo(GetFormat());
glBindTexture(mTarget, handle);
for (uint32_t i = 0; i < levels; ++i) {
glTexImage2D(mTarget, 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(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1);
}
Texture::~Texture() {
// TODO(kainino@chromium.org): delete texture (but only when not using the native texture
// constructor?)
}
GLuint Texture::GetHandle() const {
return mHandle;
}
GLenum Texture::GetGLTarget() const {
return mTarget;
}
TextureFormatInfo Texture::GetGLFormat() const {
return GetGLFormatInfo(GetFormat());
}
// TextureView
TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
}
}} // namespace backend::opengl

View File

@@ -0,0 +1,52 @@
// Copyright 2017 The Dawn 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 "dawn_native/Texture.h"
#include "glad/glad.h"
namespace backend { namespace opengl {
struct TextureFormatInfo {
GLenum internalFormat;
GLenum format;
GLenum type;
};
class Texture : public TextureBase {
public:
Texture(TextureBuilder* builder);
Texture(TextureBuilder* builder, GLuint handle);
~Texture();
GLuint GetHandle() const;
GLenum GetGLTarget() const;
TextureFormatInfo GetGLFormat() const;
private:
GLuint mHandle;
GLenum mTarget;
};
class TextureView : public TextureViewBase {
public:
TextureView(TextureViewBuilder* builder);
};
}} // namespace backend::opengl
#endif // BACKEND_OPENGL_TEXTUREGL_H_