tint->dawn: Move src/dawn_native -> src/dawn/native

Bug: dawn:1275
Change-Id: Ic60a00107a015bc677ff929c492f1085ffc38482
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/79083
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
Ben Clayton
2022-02-04 17:07:46 +00:00
committed by Dawn LUCI CQ
parent b2c4d7a244
commit 818001d32e
544 changed files with 3425 additions and 3397 deletions

View File

@@ -0,0 +1,305 @@
// Copyright 2019 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/BackendGL.h"
#include "dawn/common/GPUInfo.h"
#include "dawn/common/Log.h"
#include "dawn/native/Instance.h"
#include "dawn/native/OpenGLBackend.h"
#include "dawn/native/opengl/DeviceGL.h"
#include <cstring>
namespace dawn::native::opengl {
namespace {
struct Vendor {
const char* vendorName;
uint32_t vendorId;
};
const Vendor kVendors[] = {{"ATI", gpu_info::kVendorID_AMD},
{"ARM", gpu_info::kVendorID_ARM},
{"Imagination", gpu_info::kVendorID_ImgTec},
{"Intel", gpu_info::kVendorID_Intel},
{"NVIDIA", gpu_info::kVendorID_Nvidia},
{"Qualcomm", gpu_info::kVendorID_Qualcomm}};
uint32_t GetVendorIdFromVendors(const char* vendor) {
uint32_t vendorId = 0;
for (const auto& it : kVendors) {
// Matching vendor name with vendor string
if (strstr(vendor, it.vendorName) != nullptr) {
vendorId = it.vendorId;
break;
}
}
return vendorId;
}
void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
const char* sourceText;
switch (source) {
case GL_DEBUG_SOURCE_API:
sourceText = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
sourceText = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
sourceText = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
sourceText = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
sourceText = "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
sourceText = "Other";
break;
default:
sourceText = "UNKNOWN";
break;
}
const char* severityText;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
severityText = "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
severityText = "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
severityText = "Low";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severityText = "Notification";
break;
default:
severityText = "UNKNOWN";
break;
}
if (type == GL_DEBUG_TYPE_ERROR) {
dawn::WarningLog() << "OpenGL error:"
<< "\n Source: " << sourceText //
<< "\n ID: " << id //
<< "\n Severity: " << severityText //
<< "\n Message: " << message;
// Abort on an error when in Debug mode.
UNREACHABLE();
}
}
} // anonymous namespace
// The OpenGL backend's Adapter.
class Adapter : public AdapterBase {
public:
Adapter(InstanceBase* instance, wgpu::BackendType backendType)
: AdapterBase(instance, backendType) {
}
MaybeError InitializeGLFunctions(void* (*getProc)(const char*)) {
// Use getProc to populate the dispatch table
return mFunctions.Initialize(getProc);
}
~Adapter() override = default;
// AdapterBase Implementation
bool SupportsExternalImages() const override {
// Via dawn::native::opengl::WrapExternalEGLImage
return GetBackendType() == wgpu::BackendType::OpenGLES;
}
private:
MaybeError InitializeImpl() override {
if (mFunctions.GetVersion().IsES()) {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES);
} else {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGL);
}
// Use the debug output functionality to get notified about GL errors
// TODO(cwallez@chromium.org): add support for the KHR_debug and ARB_debug_output
// extensions
bool hasDebugOutput = mFunctions.IsAtLeastGL(4, 3) || mFunctions.IsAtLeastGLES(3, 2);
if (GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
mFunctions.Enable(GL_DEBUG_OUTPUT);
mFunctions.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
// Any GL error; dangerous undefined behavior; any shader compiler and linker errors
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH,
0, nullptr, GL_TRUE);
// Severe performance warnings; GLSL or other shader compiler and linker warnings;
// use of currently deprecated behavior
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM,
0, nullptr, GL_TRUE);
// Performance warnings from redundant state changes; trivial undefined behavior
// This is disabled because we do an incredible amount of redundant state changes.
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
nullptr, GL_FALSE);
// Any message which is not an error or performance concern
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr,
GL_FALSE);
mFunctions.DebugMessageCallback(&OnGLDebugMessage, nullptr);
}
// Set state that never changes between devices.
mFunctions.Enable(GL_DEPTH_TEST);
mFunctions.Enable(GL_SCISSOR_TEST);
mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
if (mFunctions.GetVersion().IsDesktop()) {
// These are not necessary on GLES. The functionality is enabled by default, and
// works by specifying sample counts and SRGB textures, respectively.
mFunctions.Enable(GL_MULTISAMPLE);
mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
}
mFunctions.Enable(GL_SAMPLE_MASK);
mName = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
// Workaroud to find vendor id from vendor name
const char* vendor = reinterpret_cast<const char*>(mFunctions.GetString(GL_VENDOR));
mVendorId = GetVendorIdFromVendors(vendor);
mDriverDescription = std::string("OpenGL version ") +
reinterpret_cast<const char*>(mFunctions.GetString(GL_VERSION));
if (mName.find("SwiftShader") != std::string::npos) {
mAdapterType = wgpu::AdapterType::CPU;
}
return {};
}
MaybeError InitializeSupportedFeaturesImpl() override {
// TextureCompressionBC
{
// BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features.
bool supportsS3TC =
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc") ||
(mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_dxt1") &&
mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt3") &&
mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt5"));
// COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT and
// COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT requires both GL_EXT_texture_sRGB and
// GL_EXT_texture_compression_s3tc on desktop OpenGL drivers.
// (https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB.txt)
bool supportsTextureSRGB = mFunctions.IsGLExtensionSupported("GL_EXT_texture_sRGB");
// GL_EXT_texture_compression_s3tc_srgb is an extension in OpenGL ES.
// NVidia GLES drivers don't support this extension, but they do support
// GL_NV_sRGB_formats. (Note that GL_EXT_texture_sRGB does not exist on ES.
// GL_EXT_sRGB does (core in ES 3.0), but it does not automatically provide S3TC
// SRGB support even if S3TC is supported; see
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_sRGB.txt.)
bool supportsS3TCSRGB =
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc_srgb") ||
mFunctions.IsGLExtensionSupported("GL_NV_sRGB_formats");
// BC4 and BC5
bool supportsRGTC =
mFunctions.IsAtLeastGL(3, 0) ||
mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_rgtc") ||
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_rgtc");
// BC6 and BC7
bool supportsBPTC =
mFunctions.IsAtLeastGL(4, 2) ||
mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_bptc") ||
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_bptc");
if (supportsS3TC && (supportsTextureSRGB || supportsS3TCSRGB) && supportsRGTC &&
supportsBPTC) {
mSupportedFeatures.EnableFeature(dawn::native::Feature::TextureCompressionBC);
}
}
return {};
}
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override {
GetDefaultLimits(&limits->v1);
return {};
}
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
const DeviceDescriptor* descriptor) override {
// There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context.
return Device::Create(this, descriptor, mFunctions);
}
OpenGLFunctions mFunctions;
};
// Implementation of the OpenGL backend's BackendConnection
Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, backendType) {
}
std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
// The OpenGL backend needs at least "getProcAddress" to discover an adapter.
return {};
}
ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
const AdapterDiscoveryOptionsBase* optionsBase) {
// TODO(cwallez@chromium.org): For now only create a single OpenGL adapter because don't
// know how to handle MakeCurrent.
DAWN_INVALID_IF(mCreatedAdapter, "The OpenGL backend can only create a single adapter.");
ASSERT(static_cast<wgpu::BackendType>(optionsBase->backendType) == GetType());
const AdapterDiscoveryOptions* options =
static_cast<const AdapterDiscoveryOptions*>(optionsBase);
DAWN_INVALID_IF(options->getProc == nullptr,
"AdapterDiscoveryOptions::getProc must be set");
Ref<Adapter> adapter = AcquireRef(
new Adapter(GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType)));
DAWN_TRY(adapter->InitializeGLFunctions(options->getProc));
DAWN_TRY(adapter->Initialize());
mCreatedAdapter = true;
std::vector<Ref<AdapterBase>> adapters{std::move(adapter)};
return std::move(adapters);
}
BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType) {
return new Backend(instance, backendType);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,36 @@
// Copyright 2019 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 DAWNNATIVE_OPENGL_BACKENDGL_H_
#define DAWNNATIVE_OPENGL_BACKENDGL_H_
#include "dawn/native/BackendConnection.h"
namespace dawn::native::opengl {
class Backend : public BackendConnection {
public:
Backend(InstanceBase* instance, wgpu::BackendType backendType);
std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override;
ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
const AdapterDiscoveryOptionsBase* options) override;
private:
bool mCreatedAdapter = false;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_BACKENDGL_H_

View File

@@ -0,0 +1,65 @@
// Copyright 2020 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/BindGroupGL.h"
#include "dawn/native/Texture.h"
#include "dawn/native/opengl/BindGroupLayoutGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
MaybeError ValidateGLBindGroupDescriptor(const BindGroupDescriptor* descriptor) {
const BindGroupLayoutBase::BindingMap& bindingMap = descriptor->layout->GetBindingMap();
for (uint32_t i = 0; i < descriptor->entryCount; ++i) {
const BindGroupEntry& entry = descriptor->entries[i];
const auto& it = bindingMap.find(BindingNumber(entry.binding));
BindingIndex bindingIndex = it->second;
ASSERT(bindingIndex < descriptor->layout->GetBindingCount());
const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex);
if (bindingInfo.bindingType == BindingInfoType::StorageTexture) {
ASSERT(entry.textureView != nullptr);
const uint32_t textureViewLayerCount = entry.textureView->GetLayerCount();
DAWN_INVALID_IF(
textureViewLayerCount != 1 &&
textureViewLayerCount != entry.textureView->GetTexture()->GetArrayLayers(),
"%s binds %u layers. Currently the OpenGL backend only supports either binding "
"1 layer or the all layers (%u) for storage texture.",
entry.textureView, textureViewLayerCount,
entry.textureView->GetTexture()->GetArrayLayers());
}
}
return {};
}
BindGroup::BindGroup(Device* device, const BindGroupDescriptor* descriptor)
: BindGroupBase(this, device, descriptor) {
}
BindGroup::~BindGroup() = default;
void BindGroup::DestroyImpl() {
BindGroupBase::DestroyImpl();
ToBackend(GetLayout())->DeallocateBindGroup(this);
}
// static
Ref<BindGroup> BindGroup::Create(Device* device, const BindGroupDescriptor* descriptor) {
return ToBackend(descriptor->layout)->AllocateBindGroup(device, descriptor);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,41 @@
// Copyright 2020 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 DAWNNATIVE_OPENGL_BINDGROUPGL_H_
#define DAWNNATIVE_OPENGL_BINDGROUPGL_H_
#include "dawn/common/PlacementAllocated.h"
#include "dawn/native/BindGroup.h"
namespace dawn::native::opengl {
class Device;
MaybeError ValidateGLBindGroupDescriptor(const BindGroupDescriptor* descriptor);
class BindGroup final : public BindGroupBase, public PlacementAllocated {
public:
static Ref<BindGroup> Create(Device* device, const BindGroupDescriptor* descriptor);
BindGroup(Device* device, const BindGroupDescriptor* descriptor);
private:
~BindGroup() override;
void DestroyImpl() override;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_BINDGROUPGL_H_

View File

@@ -0,0 +1,37 @@
// Copyright 2020 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/BindGroupLayoutGL.h"
#include "dawn/native/opengl/BindGroupGL.h"
namespace dawn::native::opengl {
BindGroupLayout::BindGroupLayout(DeviceBase* device,
const BindGroupLayoutDescriptor* descriptor,
PipelineCompatibilityToken pipelineCompatibilityToken)
: BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken),
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
}
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
const BindGroupDescriptor* descriptor) {
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
}
void BindGroupLayout::DeallocateBindGroup(BindGroup* bindGroup) {
mBindGroupAllocator.Deallocate(bindGroup);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,42 @@
// Copyright 2020 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 DAWNNATIVE_OPENGL_BINDGROUPLAYOUTGL_H_
#define DAWNNATIVE_OPENGL_BINDGROUPLAYOUTGL_H_
#include "dawn/common/SlabAllocator.h"
#include "dawn/native/BindGroupLayout.h"
namespace dawn::native::opengl {
class BindGroup;
class Device;
class BindGroupLayout final : public BindGroupLayoutBase {
public:
BindGroupLayout(DeviceBase* device,
const BindGroupLayoutDescriptor* descriptor,
PipelineCompatibilityToken pipelineCompatibilityToken);
Ref<BindGroup> AllocateBindGroup(Device* device, const BindGroupDescriptor* descriptor);
void DeallocateBindGroup(BindGroup* bindGroup);
private:
~BindGroupLayout() override = default;
SlabAllocator<BindGroup> mBindGroupAllocator;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_BINDGROUPLAYOUTGL_H_

View File

@@ -0,0 +1,184 @@
// 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"
#include "dawn/native/CommandBuffer.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
// Buffer
// static
ResultOrError<Ref<Buffer>> Buffer::CreateInternalBuffer(Device* device,
const BufferDescriptor* descriptor,
bool shouldLazyClear) {
Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor, shouldLazyClear));
if (descriptor->mappedAtCreation) {
DAWN_TRY(buffer->MapAtCreationInternal());
}
return std::move(buffer);
}
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
: BufferBase(device, descriptor) {
// Allocate at least 4 bytes so clamped accesses are always in bounds.
mAllocatedSize = std::max(GetSize(), uint64_t(4u));
device->gl.GenBuffers(1, &mBuffer);
device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
// The buffers with mappedAtCreation == true will be initialized in
// BufferBase::MapAtCreation().
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting) &&
!descriptor->mappedAtCreation) {
std::vector<uint8_t> clearValues(mAllocatedSize, 1u);
device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, clearValues.data(),
GL_STATIC_DRAW);
} else {
// Buffers start zeroed if you pass nullptr to glBufferData.
device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, nullptr, GL_STATIC_DRAW);
}
}
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor, bool shouldLazyClear)
: Buffer(device, descriptor) {
if (!shouldLazyClear) {
SetIsDataInitialized();
}
}
Buffer::~Buffer() = default;
GLuint Buffer::GetHandle() const {
return mBuffer;
}
bool Buffer::EnsureDataInitialized() {
if (!NeedsInitialization()) {
return false;
}
InitializeToZero();
return true;
}
bool Buffer::EnsureDataInitializedAsDestination(uint64_t offset, uint64_t size) {
if (!NeedsInitialization()) {
return false;
}
if (IsFullBufferRange(offset, size)) {
SetIsDataInitialized();
return false;
}
InitializeToZero();
return true;
}
bool Buffer::EnsureDataInitializedAsDestination(const CopyTextureToBufferCmd* copy) {
if (!NeedsInitialization()) {
return false;
}
if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
SetIsDataInitialized();
return false;
}
InitializeToZero();
return true;
}
void Buffer::InitializeToZero() {
ASSERT(NeedsInitialization());
const uint64_t size = GetAllocatedSize();
Device* device = ToBackend(GetDevice());
const std::vector<uint8_t> clearValues(size, 0u);
device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
device->gl.BufferSubData(GL_ARRAY_BUFFER, 0, size, clearValues.data());
device->IncrementLazyClearCountForTesting();
SetIsDataInitialized();
}
bool Buffer::IsCPUWritableAtCreation() const {
// TODO(enga): All buffers in GL can be mapped. Investigate if mapping them will cause the
// driver to migrate it to shared memory.
return true;
}
MaybeError Buffer::MapAtCreationImpl() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
mMappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, 0, GetSize(), GL_MAP_WRITE_BIT);
return {};
}
MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
// It is an error to map an empty range in OpenGL. We always have at least a 4-byte buffer
// so we extend the range to be 4 bytes.
if (size == 0) {
if (offset != 0) {
offset -= 4;
}
size = 4;
}
EnsureDataInitialized();
// This does GPU->CPU synchronization, we could require a high
// version of OpenGL that would let us map the buffer unsynchronized.
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* mappedData = nullptr;
if (mode & wgpu::MapMode::Read) {
mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_READ_BIT);
} else {
ASSERT(mode & wgpu::MapMode::Write);
mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT);
}
// The frontend asks that the pointer returned by GetMappedPointerImpl is from the start of
// the resource but OpenGL gives us the pointer at offset. Remove the offset.
mMappedData = static_cast<uint8_t*>(mappedData) - offset;
return {};
}
void* Buffer::GetMappedPointerImpl() {
// The mapping offset has already been removed.
return mMappedData;
}
void Buffer::UnmapImpl() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
gl.UnmapBuffer(GL_ARRAY_BUFFER);
mMappedData = nullptr;
}
void Buffer::DestroyImpl() {
BufferBase::DestroyImpl();
ToBackend(GetDevice())->gl.DeleteBuffers(1, &mBuffer);
mBuffer = 0;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,58 @@
// 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 DAWNNATIVE_OPENGL_BUFFERGL_H_
#define DAWNNATIVE_OPENGL_BUFFERGL_H_
#include "dawn/native/Buffer.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class Buffer final : public BufferBase {
public:
static ResultOrError<Ref<Buffer>> CreateInternalBuffer(Device* device,
const BufferDescriptor* descriptor,
bool shouldLazyClear);
Buffer(Device* device, const BufferDescriptor* descriptor);
GLuint GetHandle() const;
bool EnsureDataInitialized();
bool EnsureDataInitializedAsDestination(uint64_t offset, uint64_t size);
bool EnsureDataInitializedAsDestination(const CopyTextureToBufferCmd* copy);
private:
Buffer(Device* device, const BufferDescriptor* descriptor, bool shouldLazyClear);
~Buffer() override;
MaybeError MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) override;
void UnmapImpl() override;
void DestroyImpl() override;
bool IsCPUWritableAtCreation() const override;
MaybeError MapAtCreationImpl() override;
void* GetMappedPointerImpl() override;
void InitializeToZero();
GLuint mBuffer = 0;
void* mMappedData = nullptr;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_BUFFERGL_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
// 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 DAWNNATIVE_OPENGL_COMMANDBUFFERGL_H_
#define DAWNNATIVE_OPENGL_COMMANDBUFFERGL_H_
#include "dawn/native/CommandBuffer.h"
namespace dawn::native {
struct BeginRenderPassCmd;
} // namespace dawn::native
namespace dawn::native::opengl {
class Device;
struct OpenGLFunctions;
class CommandBuffer final : public CommandBufferBase {
public:
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
MaybeError Execute();
private:
MaybeError ExecuteComputePass();
MaybeError ExecuteRenderPass(BeginRenderPassCmd* renderPass);
};
// Like glTexSubImage*, the "data" argument is either a pointer to image data or
// an offset if a PBO is bound.
void DoTexSubImage(const OpenGLFunctions& gl,
const TextureCopy& destination,
const void* data,
const TextureDataLayout& dataLayout,
const Extent3D& copySize);
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_COMMANDBUFFERGL_H_

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.
#include "dawn/native/opengl/ComputePipelineGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
// static
Ref<ComputePipeline> ComputePipeline::CreateUninitialized(
Device* device,
const ComputePipelineDescriptor* descriptor) {
return AcquireRef(new ComputePipeline(device, descriptor));
}
ComputePipeline::~ComputePipeline() = default;
void ComputePipeline::DestroyImpl() {
ComputePipelineBase::DestroyImpl();
DeleteProgram(ToBackend(GetDevice())->gl);
}
MaybeError ComputePipeline::Initialize() {
DAWN_TRY(
InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
return {};
}
void ComputePipeline::ApplyNow() {
PipelineGL::ApplyNow(ToBackend(GetDevice())->gl);
}
} // namespace dawn::native::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 DAWNNATIVE_OPENGL_COMPUTEPIPELINEGL_H_
#define DAWNNATIVE_OPENGL_COMPUTEPIPELINEGL_H_
#include "dawn/native/ComputePipeline.h"
#include "dawn/native/opengl/PipelineGL.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class ComputePipeline final : public ComputePipelineBase, public PipelineGL {
public:
static Ref<ComputePipeline> CreateUninitialized(
Device* device,
const ComputePipelineDescriptor* descriptor);
void ApplyNow();
MaybeError Initialize() override;
private:
using ComputePipelineBase::ComputePipelineBase;
~ComputePipeline() override;
void DestroyImpl() override;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_COMPUTEPIPELINEGL_H_

View File

@@ -0,0 +1,315 @@
// 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/BackendConnection.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/ErrorData.h"
#include "dawn/native/StagingBuffer.h"
#include "dawn/native/opengl/BindGroupGL.h"
#include "dawn/native/opengl/BindGroupLayoutGL.h"
#include "dawn/native/opengl/BufferGL.h"
#include "dawn/native/opengl/CommandBufferGL.h"
#include "dawn/native/opengl/ComputePipelineGL.h"
#include "dawn/native/opengl/PipelineLayoutGL.h"
#include "dawn/native/opengl/QuerySetGL.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 dawn::native::opengl {
// static
ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions) {
Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions));
DAWN_TRY(device->Initialize());
return device;
}
Device::Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions)
: DeviceBase(adapter, descriptor), gl(functions) {
}
Device::~Device() {
Destroy();
}
MaybeError Device::Initialize() {
InitTogglesFromDriver();
mFormatTable = BuildGLFormatTable();
return DeviceBase::Initialize(new Queue(this));
}
void Device::InitTogglesFromDriver() {
bool supportsBaseVertex = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 2);
bool supportsBaseInstance = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(4, 2);
// TODO(crbug.com/dawn/582): Use OES_draw_buffers_indexed where available.
bool supportsIndexedDrawBuffers = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 0);
bool supportsSnormRead =
gl.IsAtLeastGL(4, 4) || gl.IsGLExtensionSupported("GL_EXT_render_snorm");
bool supportsDepthStencilRead =
gl.IsAtLeastGL(3, 0) || gl.IsGLExtensionSupported("GL_NV_read_depth_stencil");
bool supportsSampleVariables = gl.IsAtLeastGL(4, 0) || gl.IsAtLeastGLES(3, 2) ||
gl.IsGLExtensionSupported("GL_OES_sample_variables");
// TODO(crbug.com/dawn/343): We can support the extension variants, but need to load the EXT
// procs without the extension suffix.
// We'll also need emulation of shader builtins gl_BaseVertex and gl_BaseInstance.
// supportsBaseVertex |=
// (gl.IsAtLeastGLES(2, 0) &&
// (gl.IsGLExtensionSupported("OES_draw_elements_base_vertex") ||
// gl.IsGLExtensionSupported("EXT_draw_elements_base_vertex"))) ||
// (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_draw_elements_base_vertex"));
// supportsBaseInstance |=
// (gl.IsAtLeastGLES(3, 1) && gl.IsGLExtensionSupported("EXT_base_instance")) ||
// (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_base_instance"));
// TODO(crbug.com/dawn/343): Investigate emulation.
SetToggle(Toggle::DisableBaseVertex, !supportsBaseVertex);
SetToggle(Toggle::DisableBaseInstance, !supportsBaseInstance);
SetToggle(Toggle::DisableIndexedDrawBuffers, !supportsIndexedDrawBuffers);
SetToggle(Toggle::DisableSnormRead, !supportsSnormRead);
SetToggle(Toggle::DisableDepthStencilRead, !supportsDepthStencilRead);
SetToggle(Toggle::DisableSampleVariables, !supportsSampleVariables);
SetToggle(Toggle::FlushBeforeClientWaitSync, gl.GetVersion().IsES());
// For OpenGL ES, we must use dummy fragment shader for vertex-only render pipeline.
SetToggle(Toggle::UseDummyFragmentInVertexOnlyPipeline, gl.GetVersion().IsES());
}
const GLFormat& Device::GetGLFormat(const Format& format) {
ASSERT(format.isSupported);
ASSERT(format.GetIndex() < mFormatTable.size());
const GLFormat& result = mFormatTable[format.GetIndex()];
ASSERT(result.isSupportedOnBackend);
return result;
}
ResultOrError<Ref<BindGroupBase>> Device::CreateBindGroupImpl(
const BindGroupDescriptor* descriptor) {
DAWN_TRY(ValidateGLBindGroupDescriptor(descriptor));
return BindGroup::Create(this, descriptor);
}
ResultOrError<Ref<BindGroupLayoutBase>> Device::CreateBindGroupLayoutImpl(
const BindGroupLayoutDescriptor* descriptor,
PipelineCompatibilityToken pipelineCompatibilityToken) {
return AcquireRef(new BindGroupLayout(this, descriptor, pipelineCompatibilityToken));
}
ResultOrError<Ref<BufferBase>> Device::CreateBufferImpl(const BufferDescriptor* descriptor) {
return AcquireRef(new Buffer(this, descriptor));
}
ResultOrError<Ref<CommandBufferBase>> Device::CreateCommandBuffer(
CommandEncoder* encoder,
const CommandBufferDescriptor* descriptor) {
return AcquireRef(new CommandBuffer(encoder, descriptor));
}
Ref<ComputePipelineBase> Device::CreateUninitializedComputePipelineImpl(
const ComputePipelineDescriptor* descriptor) {
return ComputePipeline::CreateUninitialized(this, descriptor);
}
ResultOrError<Ref<PipelineLayoutBase>> Device::CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) {
return AcquireRef(new PipelineLayout(this, descriptor));
}
ResultOrError<Ref<QuerySetBase>> Device::CreateQuerySetImpl(
const QuerySetDescriptor* descriptor) {
return AcquireRef(new QuerySet(this, descriptor));
}
Ref<RenderPipelineBase> Device::CreateUninitializedRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return RenderPipeline::CreateUninitialized(this, descriptor);
}
ResultOrError<Ref<SamplerBase>> Device::CreateSamplerImpl(const SamplerDescriptor* descriptor) {
return AcquireRef(new Sampler(this, descriptor));
}
ResultOrError<Ref<ShaderModuleBase>> Device::CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) {
return ShaderModule::Create(this, descriptor, parseResult);
}
ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) {
return AcquireRef(new SwapChain(this, descriptor));
}
ResultOrError<Ref<NewSwapChainBase>> Device::CreateSwapChainImpl(
Surface* surface,
NewSwapChainBase* previousSwapChain,
const SwapChainDescriptor* descriptor) {
return DAWN_FORMAT_VALIDATION_ERROR("New swapchains not implemented.");
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return AcquireRef(new Texture(this, descriptor));
}
ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return AcquireRef(new TextureView(texture, descriptor));
}
void Device::SubmitFenceSync() {
GLsync sync = gl.FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
IncrementLastSubmittedCommandSerial();
mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
}
MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
::EGLImage image) {
DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
"Texture dimension (%s) is not %s.", descriptor->dimension,
wgpu::TextureDimension::e2D);
DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.",
descriptor->mipLevelCount);
DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1,
"Array layer count (%u) is not 1.", descriptor->size.depthOrArrayLayers);
DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
descriptor->sampleCount);
DAWN_INVALID_IF(descriptor->usage & (wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::StorageBinding),
"Texture usage (%s) cannot have %s or %s.", descriptor->usage,
wgpu::TextureUsage::TextureBinding, wgpu::TextureUsage::StorageBinding);
return {};
}
TextureBase* Device::CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
::EGLImage image) {
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
return nullptr;
}
if (ConsumedError(ValidateEGLImageCanBeWrapped(textureDescriptor, image))) {
return nullptr;
}
GLuint tex;
gl.GenTextures(1, &tex);
gl.BindTexture(GL_TEXTURE_2D, tex);
gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
GLint width, height, internalFormat;
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
if (textureDescriptor->size.width != static_cast<uint32_t>(width) ||
textureDescriptor->size.height != static_cast<uint32_t>(height) ||
textureDescriptor->size.depthOrArrayLayers != 1) {
ConsumedError(DAWN_FORMAT_VALIDATION_ERROR(
"EGLImage size (width: %u, height: %u, depth: 1) doesn't match descriptor size %s.",
width, height, &textureDescriptor->size));
gl.DeleteTextures(1, &tex);
return nullptr;
}
// TODO(dawn:803): Validate the OpenGL texture format from the EGLImage against the format
// in the passed-in TextureDescriptor.
return new Texture(this, textureDescriptor, tex, TextureBase::TextureState::OwnedInternal);
}
MaybeError Device::TickImpl() {
return {};
}
ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
ExecutionSerial fenceSerial{0};
while (!mFencesInFlight.empty()) {
auto [sync, tentativeSerial] = mFencesInFlight.front();
// Fence are added in order, so we can stop searching as soon
// as we see one that's not ready.
// TODO(crbug.com/dawn/633): Remove this workaround after the deadlock issue is fixed.
if (IsToggleEnabled(Toggle::FlushBeforeClientWaitSync)) {
gl.Flush();
}
GLenum result = gl.ClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
if (result == GL_TIMEOUT_EXPIRED) {
return fenceSerial;
}
// Update fenceSerial since fence is ready.
fenceSerial = tentativeSerial;
gl.DeleteSync(sync);
mFencesInFlight.pop();
ASSERT(fenceSerial > GetCompletedCommandSerial());
}
return fenceSerial;
}
ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(size_t size) {
return DAWN_UNIMPLEMENTED_ERROR("Device unable to create staging buffer.");
}
MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) {
return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer.");
}
MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) {
return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer to texture.");
}
void Device::DestroyImpl() {
ASSERT(GetState() == State::Disconnected);
}
MaybeError Device::WaitForIdleForDestruction() {
gl.Finish();
DAWN_TRY(CheckPassedSerials());
ASSERT(mFencesInFlight.empty());
return {};
}
uint32_t Device::GetOptimalBytesPerRowAlignment() const {
return 1;
}
uint64_t Device::GetOptimalBufferToTextureCopyOffsetAlignment() const {
return 1;
}
float Device::GetTimestampPeriodInNS() const {
return 1.0f;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,131 @@
// 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 DAWNNATIVE_OPENGL_DEVICEGL_H_
#define DAWNNATIVE_OPENGL_DEVICEGL_H_
#include "dawn/native/dawn_platform.h"
#include "dawn/common/Platform.h"
#include "dawn/native/Device.h"
#include "dawn/native/QuerySet.h"
#include "dawn/native/opengl/Forward.h"
#include "dawn/native/opengl/GLFormat.h"
#include "dawn/native/opengl/OpenGLFunctions.h"
#include <queue>
// Remove windows.h macros after glad's include of windows.h
#if defined(DAWN_PLATFORM_WINDOWS)
# include "dawn/common/windows_with_undefs.h"
#endif
typedef void* EGLImage;
namespace dawn::native::opengl {
class Device final : public DeviceBase {
public:
static ResultOrError<Ref<Device>> Create(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions);
~Device() override;
MaybeError Initialize();
// Contains all the OpenGL entry points, glDoFoo is called via device->gl.DoFoo.
const OpenGLFunctions gl;
const GLFormat& GetGLFormat(const Format& format);
void SubmitFenceSync();
MaybeError ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
::EGLImage image);
TextureBase* CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
::EGLImage image);
ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
CommandEncoder* encoder,
const CommandBufferDescriptor* descriptor) override;
MaybeError TickImpl() override;
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
MaybeError CopyFromStagingToBuffer(StagingBufferBase* source,
uint64_t sourceOffset,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size) override;
MaybeError CopyFromStagingToTexture(const StagingBufferBase* source,
const TextureDataLayout& src,
TextureCopy* dst,
const Extent3D& copySizePixels) override;
uint32_t GetOptimalBytesPerRowAlignment() const override;
uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
float GetTimestampPeriodInNS() const override;
private:
Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions);
ResultOrError<Ref<BindGroupBase>> CreateBindGroupImpl(
const BindGroupDescriptor* descriptor) override;
ResultOrError<Ref<BindGroupLayoutBase>> CreateBindGroupLayoutImpl(
const BindGroupLayoutDescriptor* descriptor,
PipelineCompatibilityToken pipelineCompatibilityToken) override;
ResultOrError<Ref<BufferBase>> CreateBufferImpl(
const BufferDescriptor* descriptor) override;
ResultOrError<Ref<PipelineLayoutBase>> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
ResultOrError<Ref<QuerySetBase>> CreateQuerySetImpl(
const QuerySetDescriptor* descriptor) override;
ResultOrError<Ref<SamplerBase>> CreateSamplerImpl(
const SamplerDescriptor* descriptor) override;
ResultOrError<Ref<ShaderModuleBase>> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) override;
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override;
ResultOrError<Ref<NewSwapChainBase>> CreateSwapChainImpl(
Surface* surface,
NewSwapChainBase* previousSwapChain,
const SwapChainDescriptor* descriptor) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const TextureDescriptor* descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
Ref<ComputePipelineBase> CreateUninitializedComputePipelineImpl(
const ComputePipelineDescriptor* descriptor) override;
Ref<RenderPipelineBase> CreateUninitializedRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
void InitTogglesFromDriver();
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
void DestroyImpl() override;
MaybeError WaitForIdleForDestruction() override;
std::queue<std::pair<GLsync, ExecutionSerial>> mFencesInFlight;
GLFormatTable mFormatTable;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_DEVICEGL_H_

View File

@@ -0,0 +1,66 @@
// 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 DAWNNATIVE_OPENGL_FORWARD_H_
#define DAWNNATIVE_OPENGL_FORWARD_H_
#include "dawn/native/ToBackend.h"
namespace dawn::native::opengl {
class Adapter;
class BindGroup;
class BindGroupLayout;
class Buffer;
class CommandBuffer;
class ComputePipeline;
class Device;
class PersistentPipelineState;
class PipelineLayout;
class QuerySet;
class Queue;
class RenderPipeline;
class Sampler;
class ShaderModule;
class SwapChain;
class Texture;
class TextureView;
struct OpenGLBackendTraits {
using AdapterType = Adapter;
using BindGroupType = BindGroup;
using BindGroupLayoutType = BindGroupLayout;
using BufferType = Buffer;
using CommandBufferType = CommandBuffer;
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
using QuerySetType = QuerySet;
using QueueType = Queue;
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 dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_FORWARD_H_

View File

@@ -0,0 +1,120 @@
// Copyright 2019 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/GLFormat.h"
namespace dawn::native::opengl {
GLFormatTable BuildGLFormatTable() {
GLFormatTable table;
using Type = GLFormat::ComponentType;
auto AddFormat = [&table](wgpu::TextureFormat dawnFormat, GLenum internalFormat,
GLenum format, GLenum type, Type componentType) {
size_t index = ComputeFormatIndex(dawnFormat);
ASSERT(index < table.size());
table[index].internalFormat = internalFormat;
table[index].format = format;
table[index].type = type;
table[index].componentType = componentType;
table[index].isSupportedOnBackend = true;
};
// It's dangerous to go alone, take this:
//
// [ANGLE's formatutils.cpp]
// [ANGLE's formatutilsgl.cpp]
//
// The format tables in these files are extremely complete and the best reference on GL
// format support, enums, etc.
// clang-format off
// 1 byte color formats
AddFormat(wgpu::TextureFormat::R8Unorm, GL_R8, GL_RED, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::R8Snorm, GL_R8_SNORM, GL_RED, GL_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::R8Uint, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, Type::Uint);
AddFormat(wgpu::TextureFormat::R8Sint, GL_R8I, GL_RED_INTEGER, GL_BYTE, Type::Int);
// 2 bytes color formats
AddFormat(wgpu::TextureFormat::R16Uint, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, Type::Uint);
AddFormat(wgpu::TextureFormat::R16Sint, GL_R16I, GL_RED_INTEGER, GL_SHORT, Type::Int);
AddFormat(wgpu::TextureFormat::R16Float, GL_R16F, GL_RED, GL_HALF_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::RG8Unorm, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RG8Snorm, GL_RG8_SNORM, GL_RG, GL_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RG8Uint, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE, Type::Uint);
AddFormat(wgpu::TextureFormat::RG8Sint, GL_RG8I, GL_RG_INTEGER, GL_BYTE, Type::Int);
// 4 bytes color formats
AddFormat(wgpu::TextureFormat::R32Uint, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, Type::Uint);
AddFormat(wgpu::TextureFormat::R32Sint, GL_R32I, GL_RED_INTEGER, GL_INT, Type::Int);
AddFormat(wgpu::TextureFormat::R32Float, GL_R32F, GL_RED, GL_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::RG16Uint, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, Type::Uint);
AddFormat(wgpu::TextureFormat::RG16Sint, GL_RG16I, GL_RG_INTEGER, GL_SHORT, Type::Int);
AddFormat(wgpu::TextureFormat::RG16Float, GL_RG16F, GL_RG, GL_HALF_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::RGBA8Unorm, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RGBA8UnormSrgb, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RGBA8Snorm, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RGBA8Uint, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, Type::Uint);
AddFormat(wgpu::TextureFormat::RGBA8Sint, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, Type::Int);
// This doesn't have an enum for the internal format in OpenGL, so use RGBA8.
AddFormat(wgpu::TextureFormat::BGRA8Unorm, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::RGB10A2Unorm, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, Type::Float);
AddFormat(wgpu::TextureFormat::RG11B10Ufloat, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, Type::Float);
AddFormat(wgpu::TextureFormat::RGB9E5Ufloat, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, Type::Float);
// 8 bytes color formats
AddFormat(wgpu::TextureFormat::RG32Uint, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, Type::Uint);
AddFormat(wgpu::TextureFormat::RG32Sint, GL_RG32I, GL_RG_INTEGER, GL_INT, Type::Int);
AddFormat(wgpu::TextureFormat::RG32Float, GL_RG32F, GL_RG, GL_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::RGBA16Uint, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, Type::Uint);
AddFormat(wgpu::TextureFormat::RGBA16Sint, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT, Type::Int);
AddFormat(wgpu::TextureFormat::RGBA16Float, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, Type::Float);
// 16 bytes color formats
AddFormat(wgpu::TextureFormat::RGBA32Uint, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, Type::Uint);
AddFormat(wgpu::TextureFormat::RGBA32Sint, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT, Type::Int);
AddFormat(wgpu::TextureFormat::RGBA32Float, GL_RGBA32F, GL_RGBA, GL_FLOAT, Type::Float);
// Depth stencil formats
AddFormat(wgpu::TextureFormat::Depth32Float, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth24Plus, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth16Unorm, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, Type::DepthStencil);
// Block compressed formats
AddFormat(wgpu::TextureFormat::BC1RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC1RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC2RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC2RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC3RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC3RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC4RSnorm, GL_COMPRESSED_SIGNED_RED_RGTC1, GL_RED, GL_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC4RUnorm, GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC5RGSnorm, GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC5RGUnorm, GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC6HRGBFloat, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_HALF_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::BC6HRGBUfloat, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_HALF_FLOAT, Type::Float);
AddFormat(wgpu::TextureFormat::BC7RGBAUnorm, GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
AddFormat(wgpu::TextureFormat::BC7RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);
// clang-format on
return table;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,42 @@
// Copyright 2019 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 DAWNNATIVE_OPENGL_GLFORMAT_H_
#define DAWNNATIVE_OPENGL_GLFORMAT_H_
#include "dawn/native/Format.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
struct GLFormat {
GLenum internalFormat = 0;
GLenum format = 0;
GLenum type = 0;
bool isSupportedOnBackend = false;
// OpenGL has different functions depending on the format component type, for example
// glClearBufferfv is only valid on formats with the Float ComponentType
enum ComponentType { Float, Int, Uint, DepthStencil };
ComponentType componentType;
};
using GLFormatTable = std::array<GLFormat, kKnownFormatCount>;
GLFormatTable BuildGLFormatTable();
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_GLFORMAT_H_

View File

@@ -0,0 +1,88 @@
// Copyright 2019 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/NativeSwapChainImplGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
NativeSwapChainImpl::NativeSwapChainImpl(Device* device,
PresentCallback present,
void* presentUserdata)
: mPresentCallback(present), mPresentUserdata(presentUserdata), mDevice(device) {
}
NativeSwapChainImpl::~NativeSwapChainImpl() {
const OpenGLFunctions& gl = mDevice->gl;
gl.DeleteTextures(1, &mBackTexture);
gl.DeleteFramebuffers(1, &mBackFBO);
}
void NativeSwapChainImpl::Init(DawnWSIContextGL* /*context*/) {
const OpenGLFunctions& gl = mDevice->gl;
gl.GenTextures(1, &mBackTexture);
gl.BindTexture(GL_TEXTURE_2D, mBackTexture);
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
gl.GenFramebuffers(1, &mBackFBO);
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mBackTexture, 0);
}
DawnSwapChainError NativeSwapChainImpl::Configure(WGPUTextureFormat format,
WGPUTextureUsage usage,
uint32_t width,
uint32_t height) {
if (format != WGPUTextureFormat_RGBA8Unorm) {
return "unsupported format";
}
ASSERT(width > 0);
ASSERT(height > 0);
mWidth = width;
mHeight = height;
const OpenGLFunctions& gl = mDevice->gl;
gl.BindTexture(GL_TEXTURE_2D, mBackTexture);
// Reallocate the texture
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
return DAWN_SWAP_CHAIN_NO_ERROR;
}
DawnSwapChainError NativeSwapChainImpl::GetNextTexture(DawnSwapChainNextTexture* nextTexture) {
nextTexture->texture.u32 = mBackTexture;
return DAWN_SWAP_CHAIN_NO_ERROR;
}
DawnSwapChainError NativeSwapChainImpl::Present() {
const OpenGLFunctions& gl = mDevice->gl;
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.Scissor(0, 0, mWidth, mHeight);
gl.BlitFramebuffer(0, 0, mWidth, mHeight, 0, mHeight, mWidth, 0, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
mPresentCallback(mPresentUserdata);
return DAWN_SWAP_CHAIN_NO_ERROR;
}
wgpu::TextureFormat NativeSwapChainImpl::GetPreferredFormat() const {
return wgpu::TextureFormat::RGBA8Unorm;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,58 @@
// 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 DAWNNATIVE_OPENGL_NATIVESWAPCHAINIMPLGL_H_
#define DAWNNATIVE_OPENGL_NATIVESWAPCHAINIMPLGL_H_
#include "dawn/native/OpenGLBackend.h"
#include "dawn/native/dawn_platform.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class NativeSwapChainImpl {
public:
using WSIContext = DawnWSIContextGL;
NativeSwapChainImpl(Device* device, PresentCallback present, void* presentUserdata);
~NativeSwapChainImpl();
void Init(DawnWSIContextGL* context);
DawnSwapChainError Configure(WGPUTextureFormat format,
WGPUTextureUsage,
uint32_t width,
uint32_t height);
DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture);
DawnSwapChainError Present();
wgpu::TextureFormat GetPreferredFormat() const;
private:
PresentCallback mPresentCallback;
void* mPresentUserdata;
uint32_t mWidth = 0;
uint32_t mHeight = 0;
GLuint mBackFBO = 0;
GLuint mBackTexture = 0;
Device* mDevice = nullptr;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_NATIVESWAPCHAINIMPLGL_H_

View File

@@ -0,0 +1 @@
senorblanco@chromium.org

View File

@@ -0,0 +1,65 @@
// Copyright 2019 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.
// OpenGLBackend.cpp: contains the definition of symbols exported by OpenGLBackend.h so that they
// can be compiled twice: once export (shared library), once not exported (static library)
#include "dawn/native/OpenGLBackend.h"
#include "dawn/common/SwapChainUtils.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/NativeSwapChainImplGL.h"
namespace dawn::native::opengl {
AdapterDiscoveryOptions::AdapterDiscoveryOptions()
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGL) {
}
AdapterDiscoveryOptionsES::AdapterDiscoveryOptionsES()
: AdapterDiscoveryOptionsBase(WGPUBackendType_OpenGLES) {
}
DawnSwapChainImplementation CreateNativeSwapChainImpl(WGPUDevice device,
PresentCallback present,
void* presentUserdata) {
Device* backendDevice = ToBackend(FromAPI(device));
DawnSwapChainImplementation impl;
impl = CreateSwapChainImplementation(
new NativeSwapChainImpl(backendDevice, present, presentUserdata));
impl.textureUsage = WGPUTextureUsage_Present;
return impl;
}
WGPUTextureFormat GetNativeSwapChainPreferredFormat(
const DawnSwapChainImplementation* swapChain) {
NativeSwapChainImpl* impl = reinterpret_cast<NativeSwapChainImpl*>(swapChain->userData);
return static_cast<WGPUTextureFormat>(impl->GetPreferredFormat());
}
ExternalImageDescriptorEGLImage::ExternalImageDescriptorEGLImage()
: ExternalImageDescriptor(ExternalImageType::EGLImage) {
}
WGPUTexture WrapExternalEGLImage(WGPUDevice device,
const ExternalImageDescriptorEGLImage* descriptor) {
Device* backendDevice = ToBackend(FromAPI(device));
TextureBase* texture =
backendDevice->CreateTextureWrappingEGLImage(descriptor, descriptor->image);
return ToAPI(texture);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,61 @@
// Copyright 2019 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/OpenGLFunctions.h"
#include <cctype>
namespace dawn::native::opengl {
MaybeError OpenGLFunctions::Initialize(GetProcAddress getProc) {
DAWN_TRY(mVersion.Initialize(getProc));
if (mVersion.IsES()) {
DAWN_TRY(LoadOpenGLESProcs(getProc, mVersion.GetMajor(), mVersion.GetMinor()));
} else {
DAWN_TRY(LoadDesktopGLProcs(getProc, mVersion.GetMajor(), mVersion.GetMinor()));
}
InitializeSupportedGLExtensions();
return {};
}
void OpenGLFunctions::InitializeSupportedGLExtensions() {
int32_t numExtensions;
GetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (int32_t i = 0; i < numExtensions; ++i) {
const char* extensionName = reinterpret_cast<const char*>(GetStringi(GL_EXTENSIONS, i));
mSupportedGLExtensionsSet.insert(extensionName);
}
}
bool OpenGLFunctions::IsGLExtensionSupported(const char* extension) const {
ASSERT(extension != nullptr);
return mSupportedGLExtensionsSet.count(extension) != 0;
}
const OpenGLVersion& OpenGLFunctions::GetVersion() const {
return mVersion;
}
bool OpenGLFunctions::IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) const {
return mVersion.IsDesktop() && mVersion.IsAtLeast(majorVersion, minorVersion);
}
bool OpenGLFunctions::IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) const {
return mVersion.IsES() && mVersion.IsAtLeast(majorVersion, minorVersion);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,45 @@
// Copyright 2019 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 DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_
#define DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_
#include <unordered_set>
#include "dawn/native/opengl/OpenGLFunctionsBase_autogen.h"
#include "dawn/native/opengl/OpenGLVersion.h"
namespace dawn::native::opengl {
struct OpenGLFunctions : OpenGLFunctionsBase {
public:
MaybeError Initialize(GetProcAddress getProc);
const OpenGLVersion& GetVersion() const;
bool IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) const;
bool IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) const;
bool IsGLExtensionSupported(const char* extension) const;
private:
void InitializeSupportedGLExtensions();
OpenGLVersion mVersion;
std::unordered_set<std::string> mSupportedGLExtensionsSet;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_

View File

@@ -0,0 +1,76 @@
// Copyright 2020 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/OpenGLVersion.h"
#include <cctype>
#include <tuple>
namespace dawn::native::opengl {
MaybeError OpenGLVersion::Initialize(GetProcAddress getProc) {
PFNGLGETSTRINGPROC getString = reinterpret_cast<PFNGLGETSTRINGPROC>(getProc("glGetString"));
if (getString == nullptr) {
return DAWN_INTERNAL_ERROR("Couldn't load glGetString");
}
std::string version = reinterpret_cast<const char*>(getString(GL_VERSION));
if (version.find("OpenGL ES") != std::string::npos) {
// ES spec states that the GL_VERSION string will be in the following format:
// "OpenGL ES N.M vendor-specific information"
mStandard = Standard::ES;
mMajorVersion = version[10] - '0';
mMinorVersion = version[12] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 13 || !isdigit(version[13]));
} else {
// OpenGL spec states the GL_VERSION string will be in the following format:
// <version number><space><vendor-specific information>
// The version number is either of the form major number.minor number or major
// number.minor number.release number, where the numbers all have one or more
// digits
mStandard = Standard::Desktop;
mMajorVersion = version[0] - '0';
mMinorVersion = version[2] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 3 || !isdigit(version[3]));
}
return {};
}
bool OpenGLVersion::IsDesktop() const {
return mStandard == Standard::Desktop;
}
bool OpenGLVersion::IsES() const {
return mStandard == Standard::ES;
}
uint32_t OpenGLVersion::GetMajor() const {
return mMajorVersion;
}
uint32_t OpenGLVersion::GetMinor() const {
return mMinorVersion;
}
bool OpenGLVersion::IsAtLeast(uint32_t majorVersion, uint32_t minorVersion) const {
return std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion);
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,44 @@
// Copyright 2020 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 DAWNNATIVE_OPENGL_OPENGLVERSION_H_
#define DAWNNATIVE_OPENGL_OPENGLVERSION_H_
#include "dawn/native/opengl/OpenGLFunctionsBase_autogen.h"
namespace dawn::native::opengl {
struct OpenGLVersion {
public:
MaybeError Initialize(GetProcAddress getProc);
bool IsDesktop() const;
bool IsES() const;
uint32_t GetMajor() const;
uint32_t GetMinor() const;
bool IsAtLeast(uint32_t majorVersion, uint32_t minorVersion) const;
private:
enum class Standard {
Desktop,
ES,
};
uint32_t mMajorVersion;
uint32_t mMinorVersion;
Standard mStandard;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_OPENGLVERSION_H_

View File

@@ -0,0 +1,58 @@
// 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"
#include "dawn/native/opengl/OpenGLFunctions.h"
namespace dawn::native::opengl {
void PersistentPipelineState::SetDefaultState(const OpenGLFunctions& gl) {
CallGLStencilFunc(gl);
}
void PersistentPipelineState::SetStencilFuncsAndMask(const OpenGLFunctions& gl,
GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask) {
if (mStencilBackCompareFunction == stencilBackCompareFunction &&
mStencilFrontCompareFunction == stencilFrontCompareFunction &&
mStencilReadMask == stencilReadMask) {
return;
}
mStencilBackCompareFunction = stencilBackCompareFunction;
mStencilFrontCompareFunction = stencilFrontCompareFunction;
mStencilReadMask = stencilReadMask;
CallGLStencilFunc(gl);
}
void PersistentPipelineState::SetStencilReference(const OpenGLFunctions& gl,
uint32_t stencilReference) {
if (mStencilReference == stencilReference) {
return;
}
mStencilReference = stencilReference;
CallGLStencilFunc(gl);
}
void PersistentPipelineState::CallGLStencilFunc(const OpenGLFunctions& gl) {
gl.StencilFuncSeparate(GL_BACK, mStencilBackCompareFunction, mStencilReference,
mStencilReadMask);
gl.StencilFuncSeparate(GL_FRONT, mStencilFrontCompareFunction, mStencilReference,
mStencilReadMask);
}
} // namespace dawn::native::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 DAWNNATIVE_OPENGL_PERSISTENTPIPELINESTATEGL_H_
#define DAWNNATIVE_OPENGL_PERSISTENTPIPELINESTATEGL_H_
#include "dawn/native/dawn_platform.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
struct OpenGLFunctions;
class PersistentPipelineState {
public:
void SetDefaultState(const OpenGLFunctions& gl);
void SetStencilFuncsAndMask(const OpenGLFunctions& gl,
GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask);
void SetStencilReference(const OpenGLFunctions& gl, uint32_t stencilReference);
private:
void CallGLStencilFunc(const OpenGLFunctions& gl);
GLenum mStencilBackCompareFunction = GL_ALWAYS;
GLenum mStencilFrontCompareFunction = GL_ALWAYS;
GLuint mStencilReadMask = 0xffffffff;
GLuint mStencilReference = 0;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_PERSISTENTPIPELINESTATEGL_H_

View File

@@ -0,0 +1,218 @@
// 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 "dawn/common/BitSetIterator.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/Device.h"
#include "dawn/native/Pipeline.h"
#include "dawn/native/opengl/Forward.h"
#include "dawn/native/opengl/OpenGLFunctions.h"
#include "dawn/native/opengl/PipelineLayoutGL.h"
#include "dawn/native/opengl/SamplerGL.h"
#include "dawn/native/opengl/ShaderModuleGL.h"
#include <set>
#include <sstream>
namespace dawn::native::opengl {
namespace {
GLenum GLShaderType(SingleShaderStage stage) {
switch (stage) {
case SingleShaderStage::Vertex:
return GL_VERTEX_SHADER;
case SingleShaderStage::Fragment:
return GL_FRAGMENT_SHADER;
case SingleShaderStage::Compute:
return GL_COMPUTE_SHADER;
}
UNREACHABLE();
}
} // namespace
PipelineGL::PipelineGL() : mProgram(0) {
}
PipelineGL::~PipelineGL() = default;
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<ProgrammableStage>& stages) {
auto CreateShader = [](const OpenGLFunctions& gl, GLenum type,
const char* source) -> ResultOrError<GLuint> {
GLuint shader = gl.CreateShader(type);
gl.ShaderSource(shader, 1, &source, nullptr);
gl.CompileShader(shader);
GLint compileStatus = GL_FALSE;
gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == GL_FALSE) {
GLint infoLogLength = 0;
gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) {
std::vector<char> buffer(infoLogLength);
gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
return DAWN_FORMAT_VALIDATION_ERROR("%s\nProgram compilation failed:\n%s",
source, buffer.data());
}
}
return shader;
};
mProgram = gl.CreateProgram();
// Compute the set of active stages.
wgpu::ShaderStage activeStages = wgpu::ShaderStage::None;
for (SingleShaderStage stage : IterateStages(kAllStages)) {
if (stages[stage].module != nullptr) {
activeStages |= StageBit(stage);
}
}
// Create an OpenGL shader for each stage and gather the list of combined samplers.
PerStage<CombinedSamplerInfo> combinedSamplers;
bool needsDummySampler = false;
std::vector<GLuint> glShaders;
for (SingleShaderStage stage : IterateStages(activeStages)) {
const ShaderModule* module = ToBackend(stages[stage].module.Get());
std::string glsl;
DAWN_TRY_ASSIGN(glsl, module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
&combinedSamplers[stage], layout,
&needsDummySampler));
GLuint shader;
DAWN_TRY_ASSIGN(shader, CreateShader(gl, GLShaderType(stage), glsl.c_str()));
gl.AttachShader(mProgram, shader);
glShaders.push_back(shader);
}
if (needsDummySampler) {
SamplerDescriptor desc = {};
ASSERT(desc.minFilter == wgpu::FilterMode::Nearest);
ASSERT(desc.magFilter == wgpu::FilterMode::Nearest);
ASSERT(desc.mipmapFilter == wgpu::FilterMode::Nearest);
mDummySampler =
ToBackend(layout->GetDevice()->GetOrCreateSampler(&desc).AcquireSuccess());
}
// Link all the shaders together.
gl.LinkProgram(mProgram);
GLint linkStatus = GL_FALSE;
gl.GetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
GLint infoLogLength = 0;
gl.GetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) {
std::vector<char> buffer(infoLogLength);
gl.GetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]);
return DAWN_FORMAT_VALIDATION_ERROR("Program link failed:\n%s", buffer.data());
}
}
// Compute links between stages for combined samplers, then bind them to texture units
gl.UseProgram(mProgram);
const auto& indices = layout->GetBindingIndexInfo();
std::set<CombinedSampler> combinedSamplersSet;
for (SingleShaderStage stage : IterateStages(activeStages)) {
for (const CombinedSampler& combined : combinedSamplers[stage]) {
combinedSamplersSet.insert(combined);
}
}
mUnitsForSamplers.resize(layout->GetNumSamplers());
mUnitsForTextures.resize(layout->GetNumSampledTextures());
GLuint textureUnit = layout->GetTextureUnitsUsed();
for (const auto& combined : combinedSamplersSet) {
const std::string& name = combined.GetName();
GLint location = gl.GetUniformLocation(mProgram, name.c_str());
if (location == -1) {
continue;
}
gl.Uniform1i(location, textureUnit);
bool shouldUseFiltering;
{
const BindGroupLayoutBase* bgl =
layout->GetBindGroupLayout(combined.textureLocation.group);
BindingIndex bindingIndex = bgl->GetBindingIndex(combined.textureLocation.binding);
GLuint textureIndex = indices[combined.textureLocation.group][bindingIndex];
mUnitsForTextures[textureIndex].push_back(textureUnit);
shouldUseFiltering = bgl->GetBindingInfo(bindingIndex).texture.sampleType ==
wgpu::TextureSampleType::Float;
}
{
if (combined.useDummySampler) {
mDummySamplerUnits.push_back(textureUnit);
} else {
const BindGroupLayoutBase* bgl =
layout->GetBindGroupLayout(combined.samplerLocation.group);
BindingIndex bindingIndex =
bgl->GetBindingIndex(combined.samplerLocation.binding);
GLuint samplerIndex = indices[combined.samplerLocation.group][bindingIndex];
mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering});
}
}
textureUnit++;
}
for (GLuint glShader : glShaders) {
gl.DetachShader(mProgram, glShader);
gl.DeleteShader(glShader);
}
return {};
}
void PipelineGL::DeleteProgram(const OpenGLFunctions& gl) {
gl.DeleteProgram(mProgram);
}
const std::vector<PipelineGL::SamplerUnit>& PipelineGL::GetTextureUnitsForSampler(
GLuint index) const {
ASSERT(index < mUnitsForSamplers.size());
return mUnitsForSamplers[index];
}
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTextureView(GLuint index) const {
ASSERT(index < mUnitsForTextures.size());
return mUnitsForTextures[index];
}
GLuint PipelineGL::GetProgramHandle() const {
return mProgram;
}
void PipelineGL::ApplyNow(const OpenGLFunctions& gl) {
gl.UseProgram(mProgram);
for (GLuint unit : mDummySamplerUnits) {
ASSERT(mDummySampler.Get() != nullptr);
gl.BindSampler(unit, mDummySampler->GetNonFilteringHandle());
}
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,69 @@
// 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 DAWNNATIVE_OPENGL_PIPELINEGL_H_
#define DAWNNATIVE_OPENGL_PIPELINEGL_H_
#include "dawn/native/Pipeline.h"
#include "dawn/native/PerStage.h"
#include "dawn/native/opengl/opengl_platform.h"
#include <vector>
namespace dawn::native {
struct ProgrammableStage;
} // namespace dawn::native
namespace dawn::native::opengl {
struct OpenGLFunctions;
class PipelineLayout;
class Sampler;
class PipelineGL {
public:
PipelineGL();
~PipelineGL();
// For each unit a sampler is bound to we need to know if we should use filtering or not
// because int and uint texture are only complete without filtering.
struct SamplerUnit {
GLuint unit;
bool shouldUseFiltering;
};
const std::vector<SamplerUnit>& GetTextureUnitsForSampler(GLuint index) const;
const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const;
GLuint GetProgramHandle() const;
protected:
void ApplyNow(const OpenGLFunctions& gl);
MaybeError InitializeBase(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<ProgrammableStage>& stages);
void DeleteProgram(const OpenGLFunctions& gl);
private:
GLuint mProgram;
std::vector<std::vector<SamplerUnit>> mUnitsForSamplers;
std::vector<std::vector<GLuint>> mUnitsForTextures;
std::vector<GLuint> mDummySamplerUnits;
// TODO(enga): This could live on the Device, or elsewhere, but currently it makes Device
// destruction complex as it requires the sampler to be destroyed before the sampler cache.
Ref<Sampler> mDummySampler;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_PIPELINEGL_H_

View File

@@ -0,0 +1,95 @@
// 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 "dawn/common/BitSetIterator.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
PipelineLayout::PipelineLayout(Device* device, const PipelineLayoutDescriptor* descriptor)
: PipelineLayoutBase(device, descriptor) {
GLuint uboIndex = 0;
GLuint samplerIndex = 0;
GLuint sampledTextureIndex = 0;
GLuint ssboIndex = 0;
GLuint storageTextureIndex = 0;
for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) {
const BindGroupLayoutBase* bgl = GetBindGroupLayout(group);
mIndexInfo[group].resize(bgl->GetBindingCount());
for (BindingIndex bindingIndex{0}; bindingIndex < bgl->GetBindingCount();
++bindingIndex) {
const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer:
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
mIndexInfo[group][bindingIndex] = uboIndex;
uboIndex++;
break;
case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage:
mIndexInfo[group][bindingIndex] = ssboIndex;
ssboIndex++;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
break;
case BindingInfoType::Sampler:
mIndexInfo[group][bindingIndex] = samplerIndex;
samplerIndex++;
break;
case BindingInfoType::Texture:
case BindingInfoType::ExternalTexture:
mIndexInfo[group][bindingIndex] = sampledTextureIndex;
sampledTextureIndex++;
break;
case BindingInfoType::StorageTexture:
mIndexInfo[group][bindingIndex] = storageTextureIndex;
storageTextureIndex++;
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 dawn::native::opengl

View File

@@ -0,0 +1,50 @@
// 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 DAWNNATIVE_OPENGL_PIPELINELAYOUTGL_H_
#define DAWNNATIVE_OPENGL_PIPELINELAYOUTGL_H_
#include "dawn/native/PipelineLayout.h"
#include "dawn/common/ityp_array.h"
#include "dawn/common/ityp_vector.h"
#include "dawn/native/BindingInfo.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class PipelineLayout final : public PipelineLayoutBase {
public:
PipelineLayout(Device* device, const PipelineLayoutDescriptor* descriptor);
using BindingIndexInfo =
ityp::array<BindGroupIndex, ityp::vector<BindingIndex, GLuint>, kMaxBindGroups>;
const BindingIndexInfo& GetBindingIndexInfo() const;
GLuint GetTextureUnitsUsed() const;
size_t GetNumSamplers() const;
size_t GetNumSampledTextures() const;
private:
~PipelineLayout() override = default;
BindingIndexInfo mIndexInfo;
size_t mNumSamplers;
size_t mNumSampledTextures;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_PIPELINELAYOUTGL_H_

View File

@@ -0,0 +1,27 @@
// Copyright 2020 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/QuerySetGL.h"
#include "dawn/native/opengl/DeviceGL.h"
namespace dawn::native::opengl {
QuerySet::QuerySet(Device* device, const QuerySetDescriptor* descriptor)
: QuerySetBase(device, descriptor) {
}
QuerySet::~QuerySet() = default;
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,34 @@
// Copyright 2020 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 DAWNNATIVE_OPENGL_QUERYSETGL_H_
#define DAWNNATIVE_OPENGL_QUERYSETGL_H_
#include "dawn/native/QuerySet.h"
namespace dawn::native::opengl {
class Device;
class QuerySet final : public QuerySetBase {
public:
QuerySet(Device* device, const QuerySetDescriptor* descriptor);
private:
~QuerySet() override;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_QUERYSETGL_H_

View File

@@ -0,0 +1,80 @@
// 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/BufferGL.h"
#include "dawn/native/opengl/CommandBufferGL.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/TextureGL.h"
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
namespace dawn::native::opengl {
Queue::Queue(Device* device) : QueueBase(device) {
}
MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) {
Device* device = ToBackend(GetDevice());
TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferGL::Execute");
for (uint32_t i = 0; i < commandCount; ++i) {
DAWN_TRY(ToBackend(commands[i])->Execute());
}
TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferGL::Execute");
device->SubmitFenceSync();
return {};
}
MaybeError Queue::WriteBufferImpl(BufferBase* buffer,
uint64_t bufferOffset,
const void* data,
size_t size) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
ToBackend(buffer)->EnsureDataInitializedAsDestination(bufferOffset, size);
gl.BindBuffer(GL_ARRAY_BUFFER, ToBackend(buffer)->GetHandle());
gl.BufferSubData(GL_ARRAY_BUFFER, bufferOffset, size, data);
return {};
}
MaybeError Queue::WriteTextureImpl(const ImageCopyTexture& destination,
const void* data,
const TextureDataLayout& dataLayout,
const Extent3D& writeSizePixel) {
DAWN_INVALID_IF(destination.aspect == wgpu::TextureAspect::StencilOnly,
"Writes to stencil textures unsupported on the OpenGL backend.");
TextureCopy textureCopy;
textureCopy.texture = destination.texture;
textureCopy.mipLevel = destination.mipLevel;
textureCopy.origin = destination.origin;
textureCopy.aspect =
SelectFormatAspects(destination.texture->GetFormat(), destination.aspect);
SubresourceRange range = GetSubresourcesAffectedByCopy(textureCopy, writeSizePixel);
if (IsCompleteSubresourceCopiedTo(destination.texture, writeSizePixel,
destination.mipLevel)) {
destination.texture->SetIsSubresourceContentInitialized(true, range);
} else {
ToBackend(destination.texture)->EnsureSubresourceContentInitialized(range);
}
DoTexSubImage(ToBackend(GetDevice())->gl, textureCopy, data, dataLayout, writeSizePixel);
return {};
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,42 @@
// 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 DAWNNATIVE_OPENGL_QUEUEGL_H_
#define DAWNNATIVE_OPENGL_QUEUEGL_H_
#include "dawn/native/Queue.h"
namespace dawn::native::opengl {
class Device;
class Queue final : public QueueBase {
public:
Queue(Device* device);
private:
MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override;
MaybeError WriteBufferImpl(BufferBase* buffer,
uint64_t bufferOffset,
const void* data,
size_t size) override;
MaybeError WriteTextureImpl(const ImageCopyTexture& destination,
const void* data,
const TextureDataLayout& dataLayout,
const Extent3D& writeSizePixel) override;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_QUEUEGL_H_

View File

@@ -0,0 +1,345 @@
// 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/DeviceGL.h"
#include "dawn/native/opengl/Forward.h"
#include "dawn/native/opengl/PersistentPipelineStateGL.h"
#include "dawn/native/opengl/UtilsGL.h"
namespace dawn::native::opengl {
namespace {
GLenum GLPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology) {
switch (primitiveTopology) {
case wgpu::PrimitiveTopology::PointList:
return GL_POINTS;
case wgpu::PrimitiveTopology::LineList:
return GL_LINES;
case wgpu::PrimitiveTopology::LineStrip:
return GL_LINE_STRIP;
case wgpu::PrimitiveTopology::TriangleList:
return GL_TRIANGLES;
case wgpu::PrimitiveTopology::TriangleStrip:
return GL_TRIANGLE_STRIP;
}
UNREACHABLE();
}
void ApplyFrontFaceAndCulling(const OpenGLFunctions& gl,
wgpu::FrontFace face,
wgpu::CullMode mode) {
// Note that we invert winding direction in OpenGL. Because Y axis is up in OpenGL,
// which is different from WebGPU and other backends (Y axis is down).
GLenum direction = (face == wgpu::FrontFace::CCW) ? GL_CW : GL_CCW;
gl.FrontFace(direction);
if (mode == wgpu::CullMode::None) {
gl.Disable(GL_CULL_FACE);
} else {
gl.Enable(GL_CULL_FACE);
GLenum cullMode = (mode == wgpu::CullMode::Front) ? GL_FRONT : GL_BACK;
gl.CullFace(cullMode);
}
}
GLenum GLBlendFactor(wgpu::BlendFactor factor, bool alpha) {
switch (factor) {
case wgpu::BlendFactor::Zero:
return GL_ZERO;
case wgpu::BlendFactor::One:
return GL_ONE;
case wgpu::BlendFactor::Src:
return GL_SRC_COLOR;
case wgpu::BlendFactor::OneMinusSrc:
return GL_ONE_MINUS_SRC_COLOR;
case wgpu::BlendFactor::SrcAlpha:
return GL_SRC_ALPHA;
case wgpu::BlendFactor::OneMinusSrcAlpha:
return GL_ONE_MINUS_SRC_ALPHA;
case wgpu::BlendFactor::Dst:
return GL_DST_COLOR;
case wgpu::BlendFactor::OneMinusDst:
return GL_ONE_MINUS_DST_COLOR;
case wgpu::BlendFactor::DstAlpha:
return GL_DST_ALPHA;
case wgpu::BlendFactor::OneMinusDstAlpha:
return GL_ONE_MINUS_DST_ALPHA;
case wgpu::BlendFactor::SrcAlphaSaturated:
return GL_SRC_ALPHA_SATURATE;
case wgpu::BlendFactor::Constant:
return alpha ? GL_CONSTANT_ALPHA : GL_CONSTANT_COLOR;
case wgpu::BlendFactor::OneMinusConstant:
return alpha ? GL_ONE_MINUS_CONSTANT_ALPHA : GL_ONE_MINUS_CONSTANT_COLOR;
}
UNREACHABLE();
}
GLenum GLBlendMode(wgpu::BlendOperation operation) {
switch (operation) {
case wgpu::BlendOperation::Add:
return GL_FUNC_ADD;
case wgpu::BlendOperation::Subtract:
return GL_FUNC_SUBTRACT;
case wgpu::BlendOperation::ReverseSubtract:
return GL_FUNC_REVERSE_SUBTRACT;
case wgpu::BlendOperation::Min:
return GL_MIN;
case wgpu::BlendOperation::Max:
return GL_MAX;
}
UNREACHABLE();
}
void ApplyColorState(const OpenGLFunctions& gl,
ColorAttachmentIndex attachment,
const ColorTargetState* state) {
GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
if (state->blend != nullptr) {
gl.Enablei(GL_BLEND, colorBuffer);
gl.BlendEquationSeparatei(colorBuffer, GLBlendMode(state->blend->color.operation),
GLBlendMode(state->blend->alpha.operation));
gl.BlendFuncSeparatei(colorBuffer,
GLBlendFactor(state->blend->color.srcFactor, false),
GLBlendFactor(state->blend->color.dstFactor, false),
GLBlendFactor(state->blend->alpha.srcFactor, true),
GLBlendFactor(state->blend->alpha.dstFactor, true));
} else {
gl.Disablei(GL_BLEND, colorBuffer);
}
gl.ColorMaski(colorBuffer, state->writeMask & wgpu::ColorWriteMask::Red,
state->writeMask & wgpu::ColorWriteMask::Green,
state->writeMask & wgpu::ColorWriteMask::Blue,
state->writeMask & wgpu::ColorWriteMask::Alpha);
}
void ApplyColorState(const OpenGLFunctions& gl, const ColorTargetState* state) {
if (state->blend != nullptr) {
gl.Enable(GL_BLEND);
gl.BlendEquationSeparate(GLBlendMode(state->blend->color.operation),
GLBlendMode(state->blend->alpha.operation));
gl.BlendFuncSeparate(GLBlendFactor(state->blend->color.srcFactor, false),
GLBlendFactor(state->blend->color.dstFactor, false),
GLBlendFactor(state->blend->alpha.srcFactor, true),
GLBlendFactor(state->blend->alpha.dstFactor, true));
} else {
gl.Disable(GL_BLEND);
}
gl.ColorMask(state->writeMask & wgpu::ColorWriteMask::Red,
state->writeMask & wgpu::ColorWriteMask::Green,
state->writeMask & wgpu::ColorWriteMask::Blue,
state->writeMask & wgpu::ColorWriteMask::Alpha);
}
bool Equal(const BlendComponent& lhs, const BlendComponent& rhs) {
return lhs.operation == rhs.operation && lhs.srcFactor == rhs.srcFactor &&
lhs.dstFactor == rhs.dstFactor;
}
GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {
switch (stencilOperation) {
case wgpu::StencilOperation::Keep:
return GL_KEEP;
case wgpu::StencilOperation::Zero:
return GL_ZERO;
case wgpu::StencilOperation::Replace:
return GL_REPLACE;
case wgpu::StencilOperation::Invert:
return GL_INVERT;
case wgpu::StencilOperation::IncrementClamp:
return GL_INCR;
case wgpu::StencilOperation::DecrementClamp:
return GL_DECR;
case wgpu::StencilOperation::IncrementWrap:
return GL_INCR_WRAP;
case wgpu::StencilOperation::DecrementWrap:
return GL_DECR_WRAP;
}
UNREACHABLE();
}
void ApplyDepthStencilState(const OpenGLFunctions& gl,
const DepthStencilState* descriptor,
PersistentPipelineState* persistentPipelineState) {
// Depth writes only occur if depth is enabled
if (descriptor->depthCompare == wgpu::CompareFunction::Always &&
!descriptor->depthWriteEnabled) {
gl.Disable(GL_DEPTH_TEST);
} else {
gl.Enable(GL_DEPTH_TEST);
}
if (descriptor->depthWriteEnabled) {
gl.DepthMask(GL_TRUE);
} else {
gl.DepthMask(GL_FALSE);
}
gl.DepthFunc(ToOpenGLCompareFunction(descriptor->depthCompare));
if (StencilTestEnabled(descriptor)) {
gl.Enable(GL_STENCIL_TEST);
} else {
gl.Disable(GL_STENCIL_TEST);
}
GLenum backCompareFunction = ToOpenGLCompareFunction(descriptor->stencilBack.compare);
GLenum frontCompareFunction = ToOpenGLCompareFunction(descriptor->stencilFront.compare);
persistentPipelineState->SetStencilFuncsAndMask(
gl, backCompareFunction, frontCompareFunction, descriptor->stencilReadMask);
gl.StencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->stencilBack.failOp),
OpenGLStencilOperation(descriptor->stencilBack.depthFailOp),
OpenGLStencilOperation(descriptor->stencilBack.passOp));
gl.StencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->stencilFront.failOp),
OpenGLStencilOperation(descriptor->stencilFront.depthFailOp),
OpenGLStencilOperation(descriptor->stencilFront.passOp));
gl.StencilMask(descriptor->stencilWriteMask);
}
} // anonymous namespace
// static
Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
Device* device,
const RenderPipelineDescriptor* descriptor) {
return AcquireRef(new RenderPipeline(device, descriptor));
}
RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
: RenderPipelineBase(device, descriptor),
mVertexArrayObject(0),
mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {
}
MaybeError RenderPipeline::Initialize() {
DAWN_TRY(
InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
CreateVAOForVertexState();
return {};
}
RenderPipeline::~RenderPipeline() = default;
void RenderPipeline::DestroyImpl() {
RenderPipelineBase::DestroyImpl();
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.DeleteVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(0);
DeleteProgram(gl);
}
GLenum RenderPipeline::GetGLPrimitiveTopology() const {
return mGlPrimitiveTopology;
}
ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes>
RenderPipeline::GetAttributesUsingVertexBuffer(VertexBufferSlot slot) const {
ASSERT(!IsError());
return mAttributesUsingVertexBuffer[slot];
}
void RenderPipeline::CreateVAOForVertexState() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.GenVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(mVertexArrayObject);
for (VertexAttributeLocation location : IterateBitSet(GetAttributeLocationsUsed())) {
const auto& attribute = GetAttribute(location);
GLuint glAttrib = static_cast<GLuint>(static_cast<uint8_t>(location));
gl.EnableVertexAttribArray(glAttrib);
mAttributesUsingVertexBuffer[attribute.vertexBufferSlot][location] = true;
const VertexBufferInfo& vertexBuffer = GetVertexBuffer(attribute.vertexBufferSlot);
if (vertexBuffer.arrayStride == 0) {
// Emulate a stride of zero (constant vertex attribute) by
// setting the attribute instance divisor to a huge number.
gl.VertexAttribDivisor(glAttrib, 0xffffffff);
} else {
switch (vertexBuffer.stepMode) {
case wgpu::VertexStepMode::Vertex:
break;
case wgpu::VertexStepMode::Instance:
gl.VertexAttribDivisor(glAttrib, 1);
break;
}
}
}
}
void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
PipelineGL::ApplyNow(gl);
ASSERT(mVertexArrayObject);
gl.BindVertexArray(mVertexArrayObject);
ApplyFrontFaceAndCulling(gl, GetFrontFace(), GetCullMode());
ApplyDepthStencilState(gl, GetDepthStencilState(), &persistentPipelineState);
gl.SampleMaski(0, GetSampleMask());
if (IsAlphaToCoverageEnabled()) {
gl.Enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
gl.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
if (IsDepthBiasEnabled()) {
gl.Enable(GL_POLYGON_OFFSET_FILL);
float depthBias = GetDepthBias();
float slopeScale = GetDepthBiasSlopeScale();
if (gl.PolygonOffsetClamp != nullptr) {
gl.PolygonOffsetClamp(slopeScale, depthBias, GetDepthBiasClamp());
} else {
gl.PolygonOffset(slopeScale, depthBias);
}
} else {
gl.Disable(GL_POLYGON_OFFSET_FILL);
}
if (!GetDevice()->IsToggleEnabled(Toggle::DisableIndexedDrawBuffers)) {
for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
ApplyColorState(gl, attachmentSlot, GetColorTargetState(attachmentSlot));
}
} else {
const ColorTargetState* prevDescriptor = nullptr;
for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
const ColorTargetState* descriptor = GetColorTargetState(attachmentSlot);
if (!prevDescriptor) {
ApplyColorState(gl, descriptor);
prevDescriptor = descriptor;
} else if ((descriptor->blend == nullptr) != (prevDescriptor->blend == nullptr)) {
// TODO(crbug.com/dawn/582): GLES < 3.2 does not support different blend states
// per color target. Add validation to prevent this as it is not.
ASSERT(false);
} else if (descriptor->blend != nullptr) {
if (!Equal(descriptor->blend->alpha, prevDescriptor->blend->alpha) ||
!Equal(descriptor->blend->color, prevDescriptor->blend->color) ||
descriptor->writeMask != prevDescriptor->writeMask) {
// TODO(crbug.com/dawn/582)
ASSERT(false);
}
}
}
}
}
} // namespace dawn::native::opengl

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.
#ifndef DAWNNATIVE_OPENGL_RENDERPIPELINEGL_H_
#define DAWNNATIVE_OPENGL_RENDERPIPELINEGL_H_
#include "dawn/native/RenderPipeline.h"
#include "dawn/native/opengl/PipelineGL.h"
#include "dawn/native/opengl/opengl_platform.h"
#include <vector>
namespace dawn::native::opengl {
class Device;
class PersistentPipelineState;
class RenderPipeline final : public RenderPipelineBase, public PipelineGL {
public:
static Ref<RenderPipeline> CreateUninitialized(Device* device,
const RenderPipelineDescriptor* descriptor);
GLenum GetGLPrimitiveTopology() const;
ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes> GetAttributesUsingVertexBuffer(
VertexBufferSlot slot) const;
void ApplyNow(PersistentPipelineState& persistentPipelineState);
MaybeError Initialize() override;
private:
RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor);
~RenderPipeline() override;
void DestroyImpl() override;
void CreateVAOForVertexState();
// TODO(yunchao.he@intel.com): vao need to be deduplicated between pipelines.
GLuint mVertexArrayObject;
GLenum mGlPrimitiveTopology;
ityp::array<VertexBufferSlot,
ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes>,
kMaxVertexBuffers>
mAttributesUsingVertexBuffer;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_RENDERPIPELINEGL_H_

View File

@@ -0,0 +1,130 @@
// 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 "dawn/common/Assert.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/UtilsGL.h"
namespace dawn::native::opengl {
namespace {
GLenum MagFilterMode(wgpu::FilterMode filter) {
switch (filter) {
case wgpu::FilterMode::Nearest:
return GL_NEAREST;
case wgpu::FilterMode::Linear:
return GL_LINEAR;
}
UNREACHABLE();
}
GLenum MinFilterMode(wgpu::FilterMode minFilter, wgpu::FilterMode mipMapFilter) {
switch (minFilter) {
case wgpu::FilterMode::Nearest:
switch (mipMapFilter) {
case wgpu::FilterMode::Nearest:
return GL_NEAREST_MIPMAP_NEAREST;
case wgpu::FilterMode::Linear:
return GL_NEAREST_MIPMAP_LINEAR;
}
case wgpu::FilterMode::Linear:
switch (mipMapFilter) {
case wgpu::FilterMode::Nearest:
return GL_LINEAR_MIPMAP_NEAREST;
case wgpu::FilterMode::Linear:
return GL_LINEAR_MIPMAP_LINEAR;
}
}
UNREACHABLE();
}
GLenum WrapMode(wgpu::AddressMode mode) {
switch (mode) {
case wgpu::AddressMode::Repeat:
return GL_REPEAT;
case wgpu::AddressMode::MirrorRepeat:
return GL_MIRRORED_REPEAT;
case wgpu::AddressMode::ClampToEdge:
return GL_CLAMP_TO_EDGE;
}
UNREACHABLE();
}
} // namespace
Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor)
: SamplerBase(device, descriptor) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.GenSamplers(1, &mFilteringHandle);
SetupGLSampler(mFilteringHandle, descriptor, false);
gl.GenSamplers(1, &mNonFilteringHandle);
SetupGLSampler(mNonFilteringHandle, descriptor, true);
}
Sampler::~Sampler() = default;
void Sampler::DestroyImpl() {
SamplerBase::DestroyImpl();
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.DeleteSamplers(1, &mFilteringHandle);
gl.DeleteSamplers(1, &mNonFilteringHandle);
}
void Sampler::SetupGLSampler(GLuint sampler,
const SamplerDescriptor* descriptor,
bool forceNearest) {
Device* device = ToBackend(GetDevice());
const OpenGLFunctions& gl = device->gl;
if (forceNearest) {
gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
} else {
gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER,
MagFilterMode(descriptor->magFilter));
gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
}
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
gl.SamplerParameterf(sampler, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp);
gl.SamplerParameterf(sampler, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp);
if (descriptor->compare != wgpu::CompareFunction::Undefined) {
gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_FUNC,
ToOpenGLCompareFunction(descriptor->compare));
}
if (gl.IsAtLeastGL(4, 6) ||
gl.IsGLExtensionSupported("GL_EXT_texture_filter_anisotropic")) {
gl.SamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY, GetMaxAnisotropy());
}
}
GLuint Sampler::GetFilteringHandle() const {
return mFilteringHandle;
}
GLuint Sampler::GetNonFilteringHandle() const {
return mNonFilteringHandle;
}
} // namespace dawn::native::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 DAWNNATIVE_OPENGL_SAMPLERGL_H_
#define DAWNNATIVE_OPENGL_SAMPLERGL_H_
#include "dawn/native/Sampler.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class Sampler final : public SamplerBase {
public:
Sampler(Device* device, const SamplerDescriptor* descriptor);
GLuint GetFilteringHandle() const;
GLuint GetNonFilteringHandle() const;
private:
~Sampler() override;
void DestroyImpl() override;
void SetupGLSampler(GLuint sampler, const SamplerDescriptor* descriptor, bool forceNearest);
GLuint mFilteringHandle;
// This is a sampler equivalent to mFilteringHandle except that it uses NEAREST filtering
// for everything, which is important to preserve texture completeness for u/int textures.
GLuint mNonFilteringHandle;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_SAMPLERGL_H_

View File

@@ -0,0 +1,411 @@
// 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 "dawn/common/Assert.h"
#include "dawn/common/Platform.h"
#include "dawn/native/BindGroupLayout.h"
#include "dawn/native/SpirvValidation.h"
#include "dawn/native/TintUtils.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/PipelineLayoutGL.h"
#include "dawn/native/opengl/SpirvUtils.h"
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
#include <spirv_glsl.hpp>
// Tint include must be after spirv_glsl.hpp, because spirv-cross has its own
// version of spirv_headers. We also need to undef SPV_REVISION because SPIRV-Cross
// is at 3 while spirv-headers is at 4.
#undef SPV_REVISION
#include <tint/tint.h>
#include <spirv-tools/libspirv.hpp>
#include <sstream>
namespace dawn::native::opengl {
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber) {
std::ostringstream o;
o << "dawn_binding_" << static_cast<uint32_t>(group) << "_"
<< static_cast<uint32_t>(bindingNumber);
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.useDummySampler, a.samplerLocation, a.textureLocation) <
std::tie(b.useDummySampler, a.samplerLocation, b.textureLocation);
}
std::string CombinedSampler::GetName() const {
std::ostringstream o;
o << "dawn_combined";
if (useDummySampler) {
o << "_dummy_sampler";
} else {
o << "_" << static_cast<uint32_t>(samplerLocation.group) << "_"
<< static_cast<uint32_t>(samplerLocation.binding);
}
o << "_with_" << static_cast<uint32_t>(textureLocation.group) << "_"
<< static_cast<uint32_t>(textureLocation.binding);
return o.str();
}
ResultOrError<std::unique_ptr<BindingInfoArray>> ExtractSpirvInfo(
const DeviceBase* device,
const spirv_cross::Compiler& compiler,
const std::string& entryPointName,
SingleShaderStage stage) {
const auto& resources = compiler.get_shader_resources();
// Fill in bindingInfo with the SPIRV bindings
auto ExtractResourcesBinding =
[](const DeviceBase* device,
const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
const spirv_cross::Compiler& compiler, BindingInfoType bindingType,
BindingInfoArray* bindings, bool isStorageBuffer = false) -> MaybeError {
for (const auto& resource : resources) {
DAWN_INVALID_IF(
!compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding),
"No Binding decoration set for resource");
DAWN_INVALID_IF(
!compiler.get_decoration_bitset(resource.id).get(spv::DecorationDescriptorSet),
"No Descriptor Decoration set for resource");
BindingNumber bindingNumber(
compiler.get_decoration(resource.id, spv::DecorationBinding));
BindGroupIndex bindGroupIndex(
compiler.get_decoration(resource.id, spv::DecorationDescriptorSet));
DAWN_INVALID_IF(bindGroupIndex >= kMaxBindGroupsTyped,
"Bind group index over limits in the SPIRV");
const auto& [entry, inserted] =
(*bindings)[bindGroupIndex].emplace(bindingNumber, ShaderBindingInfo{});
DAWN_INVALID_IF(!inserted, "Shader has duplicate bindings");
ShaderBindingInfo* info = &entry->second;
info->id = resource.id;
info->base_type_id = resource.base_type_id;
info->bindingType = bindingType;
switch (bindingType) {
case BindingInfoType::Texture: {
spirv_cross::SPIRType::ImageType imageType =
compiler.get_type(info->base_type_id).image;
spirv_cross::SPIRType::BaseType textureComponentType =
compiler.get_type(imageType.type).basetype;
info->texture.viewDimension =
SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed);
info->texture.multisampled = imageType.ms;
info->texture.compatibleSampleTypes =
SpirvBaseTypeToSampleTypeBit(textureComponentType);
if (imageType.depth) {
DAWN_INVALID_IF(
(info->texture.compatibleSampleTypes & SampleTypeBit::Float) == 0,
"Depth textures must have a float type");
info->texture.compatibleSampleTypes = SampleTypeBit::Depth;
}
DAWN_INVALID_IF(imageType.ms && imageType.arrayed,
"Multisampled array textures aren't supported");
break;
}
case BindingInfoType::Buffer: {
// Determine buffer size, with a minimum of 1 element in the runtime
// array
spirv_cross::SPIRType type = compiler.get_type(info->base_type_id);
info->buffer.minBindingSize =
compiler.get_declared_struct_size_runtime_array(type, 1);
// Differentiate between readonly storage bindings and writable ones
// based on the NonWritable decoration.
// TODO(dawn:527): Could isStorageBuffer be determined by calling
// compiler.get_storage_class(resource.id)?
if (isStorageBuffer) {
spirv_cross::Bitset flags =
compiler.get_buffer_block_flags(resource.id);
if (flags.get(spv::DecorationNonWritable)) {
info->buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
} else {
info->buffer.type = wgpu::BufferBindingType::Storage;
}
} else {
info->buffer.type = wgpu::BufferBindingType::Uniform;
}
break;
}
case BindingInfoType::StorageTexture: {
spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id);
DAWN_INVALID_IF(!flags.get(spv::DecorationNonReadable),
"Read-write storage textures are not supported.");
info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;
spirv_cross::SPIRType::ImageType imageType =
compiler.get_type(info->base_type_id).image;
wgpu::TextureFormat storageTextureFormat =
SpirvImageFormatToTextureFormat(imageType.format);
DAWN_INVALID_IF(storageTextureFormat == wgpu::TextureFormat::Undefined,
"Invalid image format declaration on storage image.");
const Format& format = device->GetValidInternalFormat(storageTextureFormat);
DAWN_INVALID_IF(!format.supportsStorageUsage,
"The storage texture format (%s) is not supported.",
storageTextureFormat);
DAWN_INVALID_IF(imageType.ms,
"Multisampled storage textures aren't supported.");
DAWN_INVALID_IF(imageType.depth,
"Depth storage textures aren't supported.");
info->storageTexture.format = storageTextureFormat;
info->storageTexture.viewDimension =
SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed);
break;
}
case BindingInfoType::Sampler: {
info->sampler.isComparison = false;
break;
}
case BindingInfoType::ExternalTexture: {
return DAWN_FORMAT_VALIDATION_ERROR("External textures are not supported.");
}
}
}
return {};
};
std::unique_ptr<BindingInfoArray> resultBindings = std::make_unique<BindingInfoArray>();
BindingInfoArray* bindings = resultBindings.get();
DAWN_TRY(ExtractResourcesBinding(device, resources.uniform_buffers, compiler,
BindingInfoType::Buffer, bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.separate_images, compiler,
BindingInfoType::Texture, bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.separate_samplers, compiler,
BindingInfoType::Sampler, bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.storage_buffers, compiler,
BindingInfoType::Buffer, bindings, true));
// ReadonlyStorageTexture is used as a tag to do general storage texture handling.
DAWN_TRY(ExtractResourcesBinding(device, resources.storage_images, compiler,
BindingInfoType::StorageTexture, resultBindings.get()));
return {std::move(resultBindings)};
}
// static
ResultOrError<Ref<ShaderModule>> ShaderModule::Create(Device* device,
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) {
Ref<ShaderModule> module = AcquireRef(new ShaderModule(device, descriptor));
DAWN_TRY(module->Initialize(parseResult));
return module;
}
ShaderModule::ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor)
: ShaderModuleBase(device, descriptor) {
}
// static
ResultOrError<BindingInfoArrayTable> ShaderModule::ReflectShaderUsingSPIRVCross(
DeviceBase* device,
const std::vector<uint32_t>& spirv) {
BindingInfoArrayTable result;
spirv_cross::Compiler compiler(spirv);
for (const spirv_cross::EntryPoint& entryPoint : compiler.get_entry_points_and_stages()) {
ASSERT(result.count(entryPoint.name) == 0);
SingleShaderStage stage = ExecutionModelToShaderStage(entryPoint.execution_model);
compiler.set_entry_point(entryPoint.name, entryPoint.execution_model);
std::unique_ptr<BindingInfoArray> bindings;
DAWN_TRY_ASSIGN(bindings, ExtractSpirvInfo(device, compiler, entryPoint.name, stage));
result[entryPoint.name] = std::move(bindings);
}
return std::move(result);
}
MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult) {
ScopedTintICEHandler scopedICEHandler(GetDevice());
DAWN_TRY(InitializeBase(parseResult));
// Tint currently does not support emitting GLSL, so when provided a Tint program need to
// generate SPIRV and SPIRV-Cross reflection data to be used in this backend.
tint::writer::spirv::Options options;
options.disable_workgroup_init = GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
auto result = tint::writer::spirv::Generate(GetTintProgram(), options);
DAWN_INVALID_IF(!result.success, "An error occured while generating SPIR-V: %s.",
result.error);
DAWN_TRY_ASSIGN(mGLBindings, ReflectShaderUsingSPIRVCross(GetDevice(), result.spirv));
return {};
}
ResultOrError<std::string> ShaderModule::TranslateToGLSL(const char* entryPointName,
SingleShaderStage stage,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsDummySampler) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
tint::transform::SingleEntryPoint singleEntryPointTransform;
tint::transform::DataMap transformInputs;
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
tint::Program program;
{
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");
DAWN_TRY_ASSIGN(program, RunTransforms(&singleEntryPointTransform, GetTintProgram(),
transformInputs, nullptr, nullptr));
}
tint::writer::spirv::Options tintOptions;
tintOptions.disable_workgroup_init =
GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
std::vector<uint32_t> spirv;
{
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "tint::writer::spirv::Generate");
auto result = tint::writer::spirv::Generate(&program, tintOptions);
DAWN_INVALID_IF(!result.success, "An error occured while generating SPIR-V: %s.",
result.error);
spirv = std::move(result.spirv);
}
DAWN_TRY(
ValidateSpirv(GetDevice(), spirv, GetDevice()->IsToggleEnabled(Toggle::DumpShaders)));
// If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to
// be updated.
spirv_cross::CompilerGLSL::Options options;
// The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is
// [0, w] in D3D12, Metal and Vulkan, so we should normalize it in shaders in all
// backends. See the documentation of
// spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for more details.
options.vertex.flip_vert_y = true;
options.vertex.fixup_clipspace = true;
const OpenGLVersion& version = ToBackend(GetDevice())->gl.GetVersion();
if (version.IsDesktop()) {
// The computation of GLSL version below only works for 3.3 and above.
ASSERT(version.IsAtLeast(3, 3));
}
options.es = version.IsES();
options.version = version.GetMajor() * 100 + version.GetMinor() * 10;
spirv_cross::CompilerGLSL compiler(std::move(spirv));
compiler.set_common_options(options);
compiler.set_entry_point(entryPointName, ShaderStageToExecutionModel(stage));
// Analyzes all OpImageFetch opcodes and checks if there are instances where
// said instruction is used without a combined image sampler.
// GLSL does not support texelFetch without a sampler.
// To workaround this, we must inject a dummy sampler which can be used to form a sampler2D
// at the call-site of texelFetch as necessary.
spirv_cross::VariableID dummySamplerId = compiler.build_dummy_sampler_for_combined_images();
// 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()) {
combinedSamplers->emplace_back();
CombinedSampler* info = &combinedSamplers->back();
if (combined.sampler_id == dummySamplerId) {
*needsDummySampler = true;
info->useDummySampler = true;
info->samplerLocation = {};
} else {
info->useDummySampler = false;
info->samplerLocation.group = BindGroupIndex(
compiler.get_decoration(combined.sampler_id, spv::DecorationDescriptorSet));
info->samplerLocation.binding = BindingNumber(
compiler.get_decoration(combined.sampler_id, spv::DecorationBinding));
}
info->textureLocation.group = BindGroupIndex(
compiler.get_decoration(combined.image_id, spv::DecorationDescriptorSet));
info->textureLocation.binding =
BindingNumber(compiler.get_decoration(combined.image_id, spv::DecorationBinding));
compiler.set_name(combined.combined_id, info->GetName());
}
const BindingInfoArray& bindingInfo = *(mGLBindings.at(entryPointName));
// 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.
const PipelineLayout::BindingIndexInfo& indices = layout->GetBindingIndexInfo();
// Modify the decoration of variables so that SPIRV-Cross outputs only
// layout(binding=<index>) for interface variables.
//
// Tint is used for the reflection of bindings for the implicit pipeline layout and
// pipeline/layout validation, but bindingInfo is set to mGLEntryPoints which is the
// SPIRV-Cross reflection. Tint reflects bindings used more precisely than SPIRV-Cross so
// some bindings in bindingInfo might not exist in the layout and querying the layout for
// them would cause an ASSERT. That's why we defensively check that bindings are in the
// layout before modifying them. This slight hack is ok because in the long term we will use
// Tint to produce GLSL.
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
for (const auto& it : bindingInfo[group]) {
const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(group);
BindingNumber bindingNumber = it.first;
const auto& info = it.second;
if (!bgl->HasBinding(bindingNumber)) {
continue;
}
// Remove the name of the base type. This works around an issue where if the SPIRV
// has two uniform/storage interface variables that point to the same base type,
// then SPIRV-Cross would emit two bindings with type names that conflict:
//
// layout(binding=0) uniform Buf {...} binding0;
// layout(binding=1) uniform Buf {...} binding1;
compiler.set_name(info.base_type_id, "");
BindingIndex bindingIndex = bgl->GetBindingIndex(bindingNumber);
compiler.unset_decoration(info.id, spv::DecorationDescriptorSet);
compiler.set_decoration(info.id, spv::DecorationBinding,
indices[group][bindingIndex]);
}
}
std::string glsl = compiler.compile();
if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
std::ostringstream dumpedMsg;
dumpedMsg << "/* Dumped generated GLSL */" << std::endl << glsl;
GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
}
return glsl;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,75 @@
// 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 DAWNNATIVE_OPENGL_SHADERMODULEGL_H_
#define DAWNNATIVE_OPENGL_SHADERMODULEGL_H_
#include "dawn/native/ShaderModule.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class PipelineLayout;
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber);
struct BindingLocation {
BindGroupIndex group;
BindingNumber binding;
};
bool operator<(const BindingLocation& a, const BindingLocation& b);
struct CombinedSampler {
BindingLocation samplerLocation;
BindingLocation textureLocation;
// OpenGL requires a sampler with texelFetch. If this is true, the developer did not provide
// one and Dawn should bind a dummy non-filtering sampler. |samplerLocation| is unused.
bool useDummySampler;
std::string GetName() const;
};
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
using CombinedSamplerInfo = std::vector<CombinedSampler>;
using BindingInfoArrayTable =
std::unordered_map<std::string, std::unique_ptr<BindingInfoArray>>;
class ShaderModule final : public ShaderModuleBase {
public:
static ResultOrError<Ref<ShaderModule>> Create(Device* device,
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult);
ResultOrError<std::string> TranslateToGLSL(const char* entryPointName,
SingleShaderStage stage,
CombinedSamplerInfo* combinedSamplers,
const PipelineLayout* layout,
bool* needsDummySampler) const;
private:
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
~ShaderModule() override = default;
MaybeError Initialize(ShaderModuleParseResult* parseResult);
static ResultOrError<BindingInfoArrayTable> ReflectShaderUsingSPIRVCross(
DeviceBase* device,
const std::vector<uint32_t>& spirv);
BindingInfoArrayTable mGLBindings;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_SHADERMODULEGL_H_

View File

@@ -0,0 +1,179 @@
// Copyright 2020 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/SpirvUtils.h"
namespace dawn::native {
spv::ExecutionModel ShaderStageToExecutionModel(SingleShaderStage stage) {
switch (stage) {
case SingleShaderStage::Vertex:
return spv::ExecutionModelVertex;
case SingleShaderStage::Fragment:
return spv::ExecutionModelFragment;
case SingleShaderStage::Compute:
return spv::ExecutionModelGLCompute;
}
UNREACHABLE();
}
SingleShaderStage ExecutionModelToShaderStage(spv::ExecutionModel model) {
switch (model) {
case spv::ExecutionModelVertex:
return SingleShaderStage::Vertex;
case spv::ExecutionModelFragment:
return SingleShaderStage::Fragment;
case spv::ExecutionModelGLCompute:
return SingleShaderStage::Compute;
default:
UNREACHABLE();
}
}
wgpu::TextureViewDimension SpirvDimToTextureViewDimension(spv::Dim dim, bool arrayed) {
switch (dim) {
case spv::Dim::Dim1D:
return wgpu::TextureViewDimension::e1D;
case spv::Dim::Dim2D:
if (arrayed) {
return wgpu::TextureViewDimension::e2DArray;
} else {
return wgpu::TextureViewDimension::e2D;
}
case spv::Dim::Dim3D:
return wgpu::TextureViewDimension::e3D;
case spv::Dim::DimCube:
if (arrayed) {
return wgpu::TextureViewDimension::CubeArray;
} else {
return wgpu::TextureViewDimension::Cube;
}
default:
UNREACHABLE();
}
}
wgpu::TextureFormat SpirvImageFormatToTextureFormat(spv::ImageFormat format) {
switch (format) {
case spv::ImageFormatR8:
return wgpu::TextureFormat::R8Unorm;
case spv::ImageFormatR8Snorm:
return wgpu::TextureFormat::R8Snorm;
case spv::ImageFormatR8ui:
return wgpu::TextureFormat::R8Uint;
case spv::ImageFormatR8i:
return wgpu::TextureFormat::R8Sint;
case spv::ImageFormatR16ui:
return wgpu::TextureFormat::R16Uint;
case spv::ImageFormatR16i:
return wgpu::TextureFormat::R16Sint;
case spv::ImageFormatR16f:
return wgpu::TextureFormat::R16Float;
case spv::ImageFormatRg8:
return wgpu::TextureFormat::RG8Unorm;
case spv::ImageFormatRg8Snorm:
return wgpu::TextureFormat::RG8Snorm;
case spv::ImageFormatRg8ui:
return wgpu::TextureFormat::RG8Uint;
case spv::ImageFormatRg8i:
return wgpu::TextureFormat::RG8Sint;
case spv::ImageFormatR32f:
return wgpu::TextureFormat::R32Float;
case spv::ImageFormatR32ui:
return wgpu::TextureFormat::R32Uint;
case spv::ImageFormatR32i:
return wgpu::TextureFormat::R32Sint;
case spv::ImageFormatRg16ui:
return wgpu::TextureFormat::RG16Uint;
case spv::ImageFormatRg16i:
return wgpu::TextureFormat::RG16Sint;
case spv::ImageFormatRg16f:
return wgpu::TextureFormat::RG16Float;
case spv::ImageFormatRgba8:
return wgpu::TextureFormat::RGBA8Unorm;
case spv::ImageFormatRgba8Snorm:
return wgpu::TextureFormat::RGBA8Snorm;
case spv::ImageFormatRgba8ui:
return wgpu::TextureFormat::RGBA8Uint;
case spv::ImageFormatRgba8i:
return wgpu::TextureFormat::RGBA8Sint;
case spv::ImageFormatRgb10A2:
return wgpu::TextureFormat::RGB10A2Unorm;
case spv::ImageFormatR11fG11fB10f:
return wgpu::TextureFormat::RG11B10Ufloat;
case spv::ImageFormatRg32f:
return wgpu::TextureFormat::RG32Float;
case spv::ImageFormatRg32ui:
return wgpu::TextureFormat::RG32Uint;
case spv::ImageFormatRg32i:
return wgpu::TextureFormat::RG32Sint;
case spv::ImageFormatRgba16ui:
return wgpu::TextureFormat::RGBA16Uint;
case spv::ImageFormatRgba16i:
return wgpu::TextureFormat::RGBA16Sint;
case spv::ImageFormatRgba16f:
return wgpu::TextureFormat::RGBA16Float;
case spv::ImageFormatRgba32f:
return wgpu::TextureFormat::RGBA32Float;
case spv::ImageFormatRgba32ui:
return wgpu::TextureFormat::RGBA32Uint;
case spv::ImageFormatRgba32i:
return wgpu::TextureFormat::RGBA32Sint;
default:
return wgpu::TextureFormat::Undefined;
}
}
wgpu::TextureComponentType SpirvBaseTypeToTextureComponentType(
spirv_cross::SPIRType::BaseType spirvBaseType) {
switch (spirvBaseType) {
case spirv_cross::SPIRType::Float:
return wgpu::TextureComponentType::Float;
case spirv_cross::SPIRType::Int:
return wgpu::TextureComponentType::Sint;
case spirv_cross::SPIRType::UInt:
return wgpu::TextureComponentType::Uint;
default:
UNREACHABLE();
}
}
SampleTypeBit SpirvBaseTypeToSampleTypeBit(spirv_cross::SPIRType::BaseType spirvBaseType) {
switch (spirvBaseType) {
case spirv_cross::SPIRType::Float:
return SampleTypeBit::Float | SampleTypeBit::UnfilterableFloat;
case spirv_cross::SPIRType::Int:
return SampleTypeBit::Sint;
case spirv_cross::SPIRType::UInt:
return SampleTypeBit::Uint;
default:
UNREACHABLE();
}
}
VertexFormatBaseType SpirvBaseTypeToVertexFormatBaseType(
spirv_cross::SPIRType::BaseType spirvBaseType) {
switch (spirvBaseType) {
case spirv_cross::SPIRType::Float:
return VertexFormatBaseType::Float;
case spirv_cross::SPIRType::Int:
return VertexFormatBaseType::Sint;
case spirv_cross::SPIRType::UInt:
return VertexFormatBaseType::Uint;
default:
UNREACHABLE();
}
}
} // namespace dawn::native

View File

@@ -0,0 +1,51 @@
// Copyright 2020 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.
// This file contains utilities to convert from-to spirv.hpp datatypes without polluting other
// headers with spirv.hpp
#ifndef DAWNNATIVE_OPENGL_SPIRV_UTILS_H_
#define DAWNNATIVE_OPENGL_SPIRV_UTILS_H_
#include "dawn/native/Format.h"
#include "dawn/native/PerStage.h"
#include "dawn/native/VertexFormat.h"
#include "dawn/native/dawn_platform.h"
#include <spirv_cross.hpp>
namespace dawn::native {
// Returns the spirv_cross equivalent for this shader stage and vice-versa.
spv::ExecutionModel ShaderStageToExecutionModel(SingleShaderStage stage);
SingleShaderStage ExecutionModelToShaderStage(spv::ExecutionModel model);
// Returns the texture view dimension for corresponding to (dim, arrayed).
wgpu::TextureViewDimension SpirvDimToTextureViewDimension(spv::Dim dim, bool arrayed);
// Returns the texture format corresponding to format.
wgpu::TextureFormat SpirvImageFormatToTextureFormat(spv::ImageFormat format);
// Returns the format "component type" corresponding to the SPIRV base type.
wgpu::TextureComponentType SpirvBaseTypeToTextureComponentType(
spirv_cross::SPIRType::BaseType spirvBaseType);
SampleTypeBit SpirvBaseTypeToSampleTypeBit(spirv_cross::SPIRType::BaseType spirvBaseType);
// Returns the VertexFormatBaseType corresponding to the SPIRV base type.
VertexFormatBaseType SpirvBaseTypeToVertexFormatBaseType(
spirv_cross::SPIRType::BaseType spirvBaseType);
} // namespace dawn::native
#endif // DAWNNATIVE_OPENGL_SPIRV_UTILS_H_

View File

@@ -0,0 +1,51 @@
// 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/opengl/DeviceGL.h"
#include "dawn/native/opengl/Forward.h"
#include "dawn/native/opengl/TextureGL.h"
#include <dawn/dawn_wsi.h>
namespace dawn::native::opengl {
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
: OldSwapChainBase(device, descriptor) {
const auto& im = GetImplementation();
im.Init(im.userData, nullptr);
}
SwapChain::~SwapChain() {
}
TextureBase* SwapChain::GetNextTextureImpl(const TextureDescriptor* descriptor) {
const auto& im = GetImplementation();
DawnSwapChainNextTexture next = {};
DawnSwapChainError error = im.GetNextTexture(im.userData, &next);
if (error) {
GetDevice()->HandleError(InternalErrorType::Internal, error);
return nullptr;
}
GLuint nativeTexture = next.texture.u32;
return new Texture(ToBackend(GetDevice()), descriptor, nativeTexture,
TextureBase::TextureState::OwnedExternal);
}
MaybeError SwapChain::OnBeforePresent(TextureViewBase*) {
return {};
}
} // namespace dawn::native::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 DAWNNATIVE_OPENGL_SWAPCHAINGL_H_
#define DAWNNATIVE_OPENGL_SWAPCHAINGL_H_
#include "dawn/native/SwapChain.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
class SwapChain final : public OldSwapChainBase {
public:
SwapChain(Device* device, const SwapChainDescriptor* descriptor);
protected:
~SwapChain() override;
TextureBase* GetNextTextureImpl(const TextureDescriptor* descriptor) override;
MaybeError OnBeforePresent(TextureViewBase* view) override;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_SWAPCHAINGL_H_

View File

@@ -0,0 +1,580 @@
// 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 "dawn/common/Assert.h"
#include "dawn/common/Constants.h"
#include "dawn/common/Math.h"
#include "dawn/native/EnumMaskIterator.h"
#include "dawn/native/opengl/BufferGL.h"
#include "dawn/native/opengl/CommandBufferGL.h"
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/UtilsGL.h"
namespace dawn::native::opengl {
namespace {
GLenum TargetForTexture(const TextureDescriptor* descriptor) {
switch (descriptor->dimension) {
case wgpu::TextureDimension::e2D:
if (descriptor->size.depthOrArrayLayers > 1) {
ASSERT(descriptor->sampleCount == 1);
return GL_TEXTURE_2D_ARRAY;
} else {
if (descriptor->sampleCount > 1) {
return GL_TEXTURE_2D_MULTISAMPLE;
} else {
return GL_TEXTURE_2D;
}
}
case wgpu::TextureDimension::e3D:
return GL_TEXTURE_3D;
case wgpu::TextureDimension::e1D:
break;
}
UNREACHABLE();
}
GLenum TargetForTextureViewDimension(wgpu::TextureViewDimension dimension,
uint32_t arrayLayerCount,
uint32_t sampleCount) {
switch (dimension) {
case wgpu::TextureViewDimension::e2D:
return (sampleCount > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
case wgpu::TextureViewDimension::e2DArray:
if (arrayLayerCount == 1) {
return (sampleCount > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
}
ASSERT(sampleCount == 1);
return GL_TEXTURE_2D_ARRAY;
case wgpu::TextureViewDimension::Cube:
return GL_TEXTURE_CUBE_MAP;
case wgpu::TextureViewDimension::CubeArray:
return GL_TEXTURE_CUBE_MAP_ARRAY;
case wgpu::TextureViewDimension::e3D:
return GL_TEXTURE_3D;
case wgpu::TextureViewDimension::e1D:
case wgpu::TextureViewDimension::Undefined:
break;
}
UNREACHABLE();
}
GLuint GenTexture(const OpenGLFunctions& gl) {
GLuint handle = 0;
gl.GenTextures(1, &handle);
return handle;
}
bool UsageNeedsTextureView(wgpu::TextureUsage usage) {
constexpr wgpu::TextureUsage kUsageNeedingTextureView =
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
return usage & kUsageNeedingTextureView;
}
bool RequiresCreatingNewTextureView(const TextureBase* texture,
const TextureViewDescriptor* textureViewDescriptor) {
if (texture->GetFormat().format != textureViewDescriptor->format) {
return true;
}
if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount) {
return true;
}
if (texture->GetNumMipLevels() != textureViewDescriptor->mipLevelCount) {
return true;
}
if (ToBackend(texture)->GetGLFormat().format == GL_DEPTH_STENCIL &&
(texture->GetUsage() & wgpu::TextureUsage::TextureBinding) != 0 &&
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
// We need a separate view for one of the depth or stencil planes
// because each glTextureView needs it's own handle to set
// GL_DEPTH_STENCIL_TEXTURE_MODE. Choose the stencil aspect for the
// extra handle since it is likely sampled less often.
return true;
}
switch (textureViewDescriptor->dimension) {
case wgpu::TextureViewDimension::Cube:
case wgpu::TextureViewDimension::CubeArray:
return true;
default:
break;
}
return false;
}
} // namespace
// Texture
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
: Texture(device, descriptor, GenTexture(device->gl), TextureState::OwnedInternal) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
uint32_t width = GetWidth();
uint32_t height = GetHeight();
uint32_t levels = GetNumMipLevels();
uint32_t arrayLayers = GetArrayLayers();
uint32_t sampleCount = GetSampleCount();
const GLFormat& glFormat = GetGLFormat();
gl.BindTexture(mTarget, mHandle);
// glTextureView() requires the value of GL_TEXTURE_IMMUTABLE_FORMAT for origtexture to be
// GL_TRUE, so the storage of the texture must be allocated with glTexStorage*D.
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTextureView.xhtml
switch (GetDimension()) {
case wgpu::TextureDimension::e2D:
if (arrayLayers > 1) {
ASSERT(!IsMultisampledTexture());
gl.TexStorage3D(mTarget, levels, glFormat.internalFormat, width, height,
arrayLayers);
} else {
if (IsMultisampledTexture()) {
gl.TexStorage2DMultisample(mTarget, sampleCount, glFormat.internalFormat,
width, height, true);
} else {
gl.TexStorage2D(mTarget, levels, glFormat.internalFormat, width, height);
}
}
break;
case wgpu::TextureDimension::e3D:
ASSERT(!IsMultisampledTexture());
ASSERT(arrayLayers == 1);
gl.TexStorage3D(mTarget, levels, glFormat.internalFormat, width, height,
GetDepth());
break;
case wgpu::TextureDimension::e1D:
UNREACHABLE();
}
// The texture is not complete if it uses mipmapping and not all levels up to
// MAX_LEVEL have been defined.
gl.TexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1);
if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
GetDevice()->ConsumedError(
ClearTexture(GetAllSubresources(), TextureBase::ClearValue::NonZero));
}
}
Texture::Texture(Device* device,
const TextureDescriptor* descriptor,
GLuint handle,
TextureState state)
: TextureBase(device, descriptor, state), mHandle(handle) {
mTarget = TargetForTexture(descriptor);
}
Texture::~Texture() {
}
void Texture::DestroyImpl() {
TextureBase::DestroyImpl();
if (GetTextureState() == TextureState::OwnedInternal) {
ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
mHandle = 0;
}
}
GLuint Texture::GetHandle() const {
return mHandle;
}
GLenum Texture::GetGLTarget() const {
return mTarget;
}
const GLFormat& Texture::GetGLFormat() const {
return ToBackend(GetDevice())->GetGLFormat(GetFormat());
}
MaybeError Texture::ClearTexture(const SubresourceRange& range,
TextureBase::ClearValue clearValue) {
// TODO(crbug.com/dawn/850): initialize the textures with compressed formats.
if (GetFormat().isCompressed) {
return {};
}
Device* device = ToBackend(GetDevice());
const OpenGLFunctions& gl = device->gl;
uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
if (GetFormat().isRenderable) {
if ((range.aspects & (Aspect::Depth | Aspect::Stencil)) != 0) {
GLfloat depth = fClearColor;
GLint stencil = clearColor;
if (range.aspects & Aspect::Depth) {
gl.DepthMask(GL_TRUE);
}
if (range.aspects & Aspect::Stencil) {
gl.StencilMask(GetStencilMaskFromStencilFormat(GetFormat().format));
}
auto DoClear = [&](Aspect aspects) {
if (aspects == (Aspect::Depth | Aspect::Stencil)) {
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
} else if (aspects == Aspect::Depth) {
gl.ClearBufferfv(GL_DEPTH, 0, &depth);
} else if (aspects == Aspect::Stencil) {
gl.ClearBufferiv(GL_STENCIL, 0, &stencil);
} else {
UNREACHABLE();
}
};
GLuint framebuffer = 0;
gl.GenFramebuffers(1, &framebuffer);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
GLenum attachment;
if (range.aspects == (Aspect::Depth | Aspect::Stencil)) {
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else if (range.aspects == Aspect::Depth) {
attachment = GL_DEPTH_ATTACHMENT;
} else if (range.aspects == Aspect::Stencil) {
attachment = GL_STENCIL_ATTACHMENT;
} else {
UNREACHABLE();
}
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
switch (GetDimension()) {
case wgpu::TextureDimension::e2D:
if (GetArrayLayers() == 1) {
Aspect aspectsToClear = Aspect::None;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, 0,
aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspectsToClear |= aspect;
}
if (aspectsToClear == Aspect::None) {
continue;
}
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment,
GetGLTarget(), GetHandle(),
static_cast<GLint>(level));
DoClear(aspectsToClear);
} else {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
Aspect aspectsToClear = Aspect::None;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer,
aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspectsToClear |= aspect;
}
if (aspectsToClear == Aspect::None) {
continue;
}
gl.FramebufferTextureLayer(
GL_DRAW_FRAMEBUFFER, attachment, GetHandle(),
static_cast<GLint>(level), static_cast<GLint>(layer));
DoClear(aspectsToClear);
}
}
break;
case wgpu::TextureDimension::e1D:
case wgpu::TextureDimension::e3D:
UNREACHABLE();
}
}
gl.DeleteFramebuffers(1, &framebuffer);
} else {
ASSERT(range.aspects == Aspect::Color);
// For gl.ClearBufferiv/uiv calls
constexpr std::array<GLuint, 4> kClearColorDataUint0 = {0u, 0u, 0u, 0u};
constexpr std::array<GLuint, 4> kClearColorDataUint1 = {1u, 1u, 1u, 1u};
std::array<GLuint, 4> clearColorData;
clearColorData.fill((clearValue == TextureBase::ClearValue::Zero) ? 0u : 1u);
// For gl.ClearBufferfv calls
constexpr std::array<GLfloat, 4> kClearColorDataFloat0 = {0.f, 0.f, 0.f, 0.f};
constexpr std::array<GLfloat, 4> kClearColorDataFloat1 = {1.f, 1.f, 1.f, 1.f};
std::array<GLfloat, 4> fClearColorData;
fClearColorData.fill((clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f);
static constexpr uint32_t MAX_TEXEL_SIZE = 16;
const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(Aspect::Color).block;
ASSERT(blockInfo.byteSize <= MAX_TEXEL_SIZE);
// For gl.ClearTexSubImage calls
constexpr std::array<GLbyte, MAX_TEXEL_SIZE> kClearColorDataBytes0 = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr std::array<GLbyte, MAX_TEXEL_SIZE> kClearColorDataBytes255 = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
wgpu::TextureComponentType baseType =
GetFormat().GetAspectInfo(Aspect::Color).baseType;
const GLFormat& glFormat = GetGLFormat();
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
Extent3D mipSize = GetMipLevelPhysicalSize(level);
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
if (gl.IsAtLeastGL(4, 4)) {
gl.ClearTexSubImage(mHandle, static_cast<GLint>(level), 0, 0,
static_cast<GLint>(layer), mipSize.width,
mipSize.height, mipSize.depthOrArrayLayers,
glFormat.format, glFormat.type,
clearValue == TextureBase::ClearValue::Zero
? kClearColorDataBytes0.data()
: kClearColorDataBytes255.data());
continue;
}
GLuint framebuffer = 0;
gl.GenFramebuffers(1, &framebuffer);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
GLenum attachment = GL_COLOR_ATTACHMENT0;
gl.DrawBuffers(1, &attachment);
gl.Disable(GL_SCISSOR_TEST);
gl.ColorMask(true, true, true, true);
auto DoClear = [&]() {
switch (baseType) {
case wgpu::TextureComponentType::Float: {
gl.ClearBufferfv(GL_COLOR, 0,
clearValue == TextureBase::ClearValue::Zero
? kClearColorDataFloat0.data()
: kClearColorDataFloat1.data());
break;
}
case wgpu::TextureComponentType::Uint: {
gl.ClearBufferuiv(GL_COLOR, 0,
clearValue == TextureBase::ClearValue::Zero
? kClearColorDataUint0.data()
: kClearColorDataUint1.data());
break;
}
case wgpu::TextureComponentType::Sint: {
gl.ClearBufferiv(GL_COLOR, 0,
reinterpret_cast<const GLint*>(
clearValue == TextureBase::ClearValue::Zero
? kClearColorDataUint0.data()
: kClearColorDataUint1.data()));
break;
}
case wgpu::TextureComponentType::DepthComparison:
UNREACHABLE();
}
};
if (GetArrayLayers() == 1) {
switch (GetDimension()) {
case wgpu::TextureDimension::e1D:
UNREACHABLE();
case wgpu::TextureDimension::e2D:
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment,
GetGLTarget(), GetHandle(), level);
DoClear();
break;
case wgpu::TextureDimension::e3D:
uint32_t depth =
GetMipLevelVirtualSize(level).depthOrArrayLayers;
for (GLint z = 0; z < static_cast<GLint>(depth); ++z) {
gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attachment,
GetHandle(), level, z);
DoClear();
}
break;
}
} else {
ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attachment, GetHandle(),
level, layer);
DoClear();
}
gl.Enable(GL_SCISSOR_TEST);
gl.DeleteFramebuffers(1, &framebuffer);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
}
}
} else {
ASSERT(range.aspects == Aspect::Color);
// create temp buffer with clear color to copy to the texture image
const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(Aspect::Color).block;
ASSERT(kTextureBytesPerRowAlignment % blockInfo.byteSize == 0);
Extent3D largestMipSize = GetMipLevelPhysicalSize(range.baseMipLevel);
uint32_t bytesPerRow =
Align((largestMipSize.width / blockInfo.width) * blockInfo.byteSize, 4);
// Make sure that we are not rounding
ASSERT(bytesPerRow % blockInfo.byteSize == 0);
ASSERT(largestMipSize.height % blockInfo.height == 0);
uint64_t bufferSize64 = static_cast<uint64_t>(bytesPerRow) *
(largestMipSize.height / blockInfo.height) *
largestMipSize.depthOrArrayLayers;
if (bufferSize64 > std::numeric_limits<size_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
}
size_t bufferSize = static_cast<size_t>(bufferSize64);
dawn::native::BufferDescriptor descriptor = {};
descriptor.mappedAtCreation = true;
descriptor.usage = wgpu::BufferUsage::CopySrc;
descriptor.size = bufferSize;
// We don't count the lazy clear of srcBuffer because it is an internal buffer.
// TODO(natlee@microsoft.com): use Dynamic Uploader here for temp buffer
Ref<Buffer> srcBuffer;
DAWN_TRY_ASSIGN(srcBuffer, Buffer::CreateInternalBuffer(device, &descriptor, false));
// Fill the buffer with clear color
memset(srcBuffer->GetMappedRange(0, bufferSize), clearColor, bufferSize);
srcBuffer->Unmap();
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, srcBuffer->GetHandle());
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
TextureCopy textureCopy;
textureCopy.texture = this;
textureCopy.mipLevel = level;
textureCopy.origin = {};
textureCopy.aspect = Aspect::Color;
TextureDataLayout dataLayout;
dataLayout.offset = 0;
dataLayout.bytesPerRow = bytesPerRow;
dataLayout.rowsPerImage = largestMipSize.height;
Extent3D mipSize = GetMipLevelPhysicalSize(level);
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
textureCopy.origin.z = layer;
DoTexSubImage(ToBackend(GetDevice())->gl, textureCopy, 0, dataLayout, mipSize);
}
}
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
if (clearValue == TextureBase::ClearValue::Zero) {
SetIsSubresourceContentInitialized(true, range);
device->IncrementLazyClearCountForTesting();
}
return {};
}
void Texture::EnsureSubresourceContentInitialized(const SubresourceRange& range) {
if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
return;
}
if (!IsSubresourceContentInitialized(range)) {
GetDevice()->ConsumedError(ClearTexture(range, TextureBase::ClearValue::Zero));
}
}
// TextureView
TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
: TextureViewBase(texture, descriptor), mOwnsHandle(false) {
mTarget = TargetForTextureViewDimension(descriptor->dimension, descriptor->arrayLayerCount,
texture->GetSampleCount());
// Texture could be destroyed by the time we make a view.
if (GetTexture()->GetTextureState() == Texture::TextureState::Destroyed) {
return;
}
if (!UsageNeedsTextureView(texture->GetUsage())) {
mHandle = 0;
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mHandle = ToBackend(texture)->GetHandle();
} else {
// glTextureView() is supported on OpenGL version >= 4.3
// TODO(crbug.com/dawn/593): support texture view on OpenGL version <= 4.2 and ES
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
mHandle = GenTexture(gl);
const Texture* textureGL = ToBackend(texture);
const GLFormat& glFormat = ToBackend(GetDevice())->GetGLFormat(GetFormat());
gl.TextureView(mHandle, mTarget, textureGL->GetHandle(), glFormat.internalFormat,
descriptor->baseMipLevel, descriptor->mipLevelCount,
descriptor->baseArrayLayer, descriptor->arrayLayerCount);
mOwnsHandle = true;
}
}
TextureView::~TextureView() {
}
void TextureView::DestroyImpl() {
TextureViewBase::DestroyImpl();
if (mOwnsHandle) {
ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
}
}
GLuint TextureView::GetHandle() const {
ASSERT(mHandle != 0);
return mHandle;
}
GLenum TextureView::GetGLTarget() const {
return mTarget;
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,69 @@
// 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 DAWNNATIVE_OPENGL_TEXTUREGL_H_
#define DAWNNATIVE_OPENGL_TEXTUREGL_H_
#include "dawn/native/Texture.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
class Device;
struct GLFormat;
class Texture final : public TextureBase {
public:
Texture(Device* device, const TextureDescriptor* descriptor);
Texture(Device* device,
const TextureDescriptor* descriptor,
GLuint handle,
TextureState state);
GLuint GetHandle() const;
GLenum GetGLTarget() const;
const GLFormat& GetGLFormat() const;
void EnsureSubresourceContentInitialized(const SubresourceRange& range);
private:
~Texture() override;
void DestroyImpl() override;
MaybeError ClearTexture(const SubresourceRange& range, TextureBase::ClearValue clearValue);
GLuint mHandle;
GLenum mTarget;
};
class TextureView final : public TextureViewBase {
public:
TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor);
GLuint GetHandle() const;
GLenum GetGLTarget() const;
private:
~TextureView() override;
void DestroyImpl() override;
GLuint mHandle;
GLenum mTarget;
bool mOwnsHandle;
};
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_TEXTUREGL_H_

View File

@@ -0,0 +1,55 @@
// Copyright 2019 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/UtilsGL.h"
#include "dawn/common/Assert.h"
namespace dawn::native::opengl {
GLuint ToOpenGLCompareFunction(wgpu::CompareFunction compareFunction) {
switch (compareFunction) {
case wgpu::CompareFunction::Never:
return GL_NEVER;
case wgpu::CompareFunction::Less:
return GL_LESS;
case wgpu::CompareFunction::LessEqual:
return GL_LEQUAL;
case wgpu::CompareFunction::Greater:
return GL_GREATER;
case wgpu::CompareFunction::GreaterEqual:
return GL_GEQUAL;
case wgpu::CompareFunction::NotEqual:
return GL_NOTEQUAL;
case wgpu::CompareFunction::Equal:
return GL_EQUAL;
case wgpu::CompareFunction::Always:
return GL_ALWAYS;
case wgpu::CompareFunction::Undefined:
break;
}
UNREACHABLE();
}
GLint GetStencilMaskFromStencilFormat(wgpu::TextureFormat depthStencilFormat) {
switch (depthStencilFormat) {
case wgpu::TextureFormat::Depth24PlusStencil8:
return 0xFF;
default:
UNREACHABLE();
}
}
} // namespace dawn::native::opengl

View File

@@ -0,0 +1,27 @@
// Copyright 2019 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 DAWNNATIVE_OPENGL_UTILSGL_H_
#define DAWNNATIVE_OPENGL_UTILSGL_H_
#include "dawn/native/dawn_platform.h"
#include "dawn/native/opengl/opengl_platform.h"
namespace dawn::native::opengl {
GLuint ToOpenGLCompareFunction(wgpu::CompareFunction compareFunction);
GLint GetStencilMaskFromStencilFormat(wgpu::TextureFormat depthStencilFormat);
} // namespace dawn::native::opengl
#endif // DAWNNATIVE_OPENGL_UTILSGL_H_

View File

@@ -0,0 +1,15 @@
// Copyright 2019 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/opengl_platform_autogen.h"

View File

@@ -0,0 +1,23 @@
{
"_comment": [
"Copyright 2019 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."
],
"supported_extensions": [
"GL_EXT_texture_compression_s3tc",
"GL_EXT_texture_compression_s3tc_srgb",
"GL_OES_EGL_image"
]
}