mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-19 09:55:26 +00:00
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:
committed by
Dawn LUCI CQ
parent
b2c4d7a244
commit
818001d32e
305
src/dawn/native/opengl/BackendGL.cpp
Normal file
305
src/dawn/native/opengl/BackendGL.cpp
Normal 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
|
||||
36
src/dawn/native/opengl/BackendGL.h
Normal file
36
src/dawn/native/opengl/BackendGL.h
Normal 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_
|
||||
65
src/dawn/native/opengl/BindGroupGL.cpp
Normal file
65
src/dawn/native/opengl/BindGroupGL.cpp
Normal 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
|
||||
41
src/dawn/native/opengl/BindGroupGL.h
Normal file
41
src/dawn/native/opengl/BindGroupGL.h
Normal 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_
|
||||
37
src/dawn/native/opengl/BindGroupLayoutGL.cpp
Normal file
37
src/dawn/native/opengl/BindGroupLayoutGL.cpp
Normal 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
|
||||
42
src/dawn/native/opengl/BindGroupLayoutGL.h
Normal file
42
src/dawn/native/opengl/BindGroupLayoutGL.h
Normal 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_
|
||||
184
src/dawn/native/opengl/BufferGL.cpp
Normal file
184
src/dawn/native/opengl/BufferGL.cpp
Normal 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
|
||||
58
src/dawn/native/opengl/BufferGL.h
Normal file
58
src/dawn/native/opengl/BufferGL.h
Normal 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_
|
||||
1488
src/dawn/native/opengl/CommandBufferGL.cpp
Normal file
1488
src/dawn/native/opengl/CommandBufferGL.cpp
Normal file
File diff suppressed because it is too large
Load Diff
49
src/dawn/native/opengl/CommandBufferGL.h
Normal file
49
src/dawn/native/opengl/CommandBufferGL.h
Normal 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_
|
||||
45
src/dawn/native/opengl/ComputePipelineGL.cpp
Normal file
45
src/dawn/native/opengl/ComputePipelineGL.cpp
Normal 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
|
||||
46
src/dawn/native/opengl/ComputePipelineGL.h
Normal file
46
src/dawn/native/opengl/ComputePipelineGL.h
Normal 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_
|
||||
315
src/dawn/native/opengl/DeviceGL.cpp
Normal file
315
src/dawn/native/opengl/DeviceGL.cpp
Normal 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
|
||||
131
src/dawn/native/opengl/DeviceGL.h
Normal file
131
src/dawn/native/opengl/DeviceGL.h
Normal 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_
|
||||
66
src/dawn/native/opengl/Forward.h
Normal file
66
src/dawn/native/opengl/Forward.h
Normal 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_
|
||||
120
src/dawn/native/opengl/GLFormat.cpp
Normal file
120
src/dawn/native/opengl/GLFormat.cpp
Normal 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
|
||||
42
src/dawn/native/opengl/GLFormat.h
Normal file
42
src/dawn/native/opengl/GLFormat.h
Normal 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_
|
||||
88
src/dawn/native/opengl/NativeSwapChainImplGL.cpp
Normal file
88
src/dawn/native/opengl/NativeSwapChainImplGL.cpp
Normal 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
|
||||
58
src/dawn/native/opengl/NativeSwapChainImplGL.h
Normal file
58
src/dawn/native/opengl/NativeSwapChainImplGL.h
Normal 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_
|
||||
1
src/dawn/native/opengl/OWNERS
Normal file
1
src/dawn/native/opengl/OWNERS
Normal file
@@ -0,0 +1 @@
|
||||
senorblanco@chromium.org
|
||||
65
src/dawn/native/opengl/OpenGLBackend.cpp
Normal file
65
src/dawn/native/opengl/OpenGLBackend.cpp
Normal 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
|
||||
61
src/dawn/native/opengl/OpenGLFunctions.cpp
Normal file
61
src/dawn/native/opengl/OpenGLFunctions.cpp
Normal 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
|
||||
45
src/dawn/native/opengl/OpenGLFunctions.h
Normal file
45
src/dawn/native/opengl/OpenGLFunctions.h
Normal 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_
|
||||
76
src/dawn/native/opengl/OpenGLVersion.cpp
Normal file
76
src/dawn/native/opengl/OpenGLVersion.cpp
Normal 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
|
||||
44
src/dawn/native/opengl/OpenGLVersion.h
Normal file
44
src/dawn/native/opengl/OpenGLVersion.h
Normal 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_
|
||||
58
src/dawn/native/opengl/PersistentPipelineStateGL.cpp
Normal file
58
src/dawn/native/opengl/PersistentPipelineStateGL.cpp
Normal 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
|
||||
45
src/dawn/native/opengl/PersistentPipelineStateGL.h
Normal file
45
src/dawn/native/opengl/PersistentPipelineStateGL.h
Normal 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_
|
||||
218
src/dawn/native/opengl/PipelineGL.cpp
Normal file
218
src/dawn/native/opengl/PipelineGL.cpp
Normal 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
|
||||
69
src/dawn/native/opengl/PipelineGL.h
Normal file
69
src/dawn/native/opengl/PipelineGL.h
Normal 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_
|
||||
95
src/dawn/native/opengl/PipelineLayoutGL.cpp
Normal file
95
src/dawn/native/opengl/PipelineLayoutGL.cpp
Normal 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
|
||||
50
src/dawn/native/opengl/PipelineLayoutGL.h
Normal file
50
src/dawn/native/opengl/PipelineLayoutGL.h
Normal 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_
|
||||
27
src/dawn/native/opengl/QuerySetGL.cpp
Normal file
27
src/dawn/native/opengl/QuerySetGL.cpp
Normal 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
|
||||
34
src/dawn/native/opengl/QuerySetGL.h
Normal file
34
src/dawn/native/opengl/QuerySetGL.h
Normal 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_
|
||||
80
src/dawn/native/opengl/QueueGL.cpp
Normal file
80
src/dawn/native/opengl/QueueGL.cpp
Normal 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
|
||||
42
src/dawn/native/opengl/QueueGL.h
Normal file
42
src/dawn/native/opengl/QueueGL.h
Normal 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_
|
||||
345
src/dawn/native/opengl/RenderPipelineGL.cpp
Normal file
345
src/dawn/native/opengl/RenderPipelineGL.cpp
Normal 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
|
||||
62
src/dawn/native/opengl/RenderPipelineGL.h
Normal file
62
src/dawn/native/opengl/RenderPipelineGL.h
Normal 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_
|
||||
130
src/dawn/native/opengl/SamplerGL.cpp
Normal file
130
src/dawn/native/opengl/SamplerGL.cpp
Normal 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
|
||||
48
src/dawn/native/opengl/SamplerGL.h
Normal file
48
src/dawn/native/opengl/SamplerGL.h
Normal 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_
|
||||
411
src/dawn/native/opengl/ShaderModuleGL.cpp
Normal file
411
src/dawn/native/opengl/ShaderModuleGL.cpp
Normal 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
|
||||
75
src/dawn/native/opengl/ShaderModuleGL.h
Normal file
75
src/dawn/native/opengl/ShaderModuleGL.h
Normal 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_
|
||||
179
src/dawn/native/opengl/SpirvUtils.cpp
Normal file
179
src/dawn/native/opengl/SpirvUtils.cpp
Normal 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
|
||||
51
src/dawn/native/opengl/SpirvUtils.h
Normal file
51
src/dawn/native/opengl/SpirvUtils.h
Normal 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_
|
||||
51
src/dawn/native/opengl/SwapChainGL.cpp
Normal file
51
src/dawn/native/opengl/SwapChainGL.cpp
Normal 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
|
||||
38
src/dawn/native/opengl/SwapChainGL.h
Normal file
38
src/dawn/native/opengl/SwapChainGL.h
Normal 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_
|
||||
580
src/dawn/native/opengl/TextureGL.cpp
Normal file
580
src/dawn/native/opengl/TextureGL.cpp
Normal 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
|
||||
69
src/dawn/native/opengl/TextureGL.h
Normal file
69
src/dawn/native/opengl/TextureGL.h
Normal 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_
|
||||
55
src/dawn/native/opengl/UtilsGL.cpp
Normal file
55
src/dawn/native/opengl/UtilsGL.cpp
Normal 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
|
||||
27
src/dawn/native/opengl/UtilsGL.h
Normal file
27
src/dawn/native/opengl/UtilsGL.h
Normal 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_
|
||||
15
src/dawn/native/opengl/opengl_platform.h
Normal file
15
src/dawn/native/opengl/opengl_platform.h
Normal 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"
|
||||
23
src/dawn/native/opengl/supported_extensions.json
Normal file
23
src/dawn/native/opengl/supported_extensions.json
Normal 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"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user