Support internal pipelines for Dawn
Like copyTextureCHROMIUM in Chromium, CopyImageBitmapToTexture can use internal pipeline to do the GPU uploading. But Dawn doesn't support internal pipeline now. This patch adds the first internal pipeline for Dawn and add the API CopyTextureForBrowser to use internal pipeline to do gpu uploading. The patch integrates very simple wgsl vertex/fragment shaders to do simple direct blit to verify the whole system works. BUG=dawn:465 Change-Id: I8b566af38a10eea00f7426c39e752958ef057abd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30960 Commit-Queue: Shaobo Yan <shaobo.yan@intel.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
131e619fe4
commit
db8766bb23
|
@ -1035,6 +1035,14 @@
|
||||||
{"name": "data layout", "type": "texture data layout", "annotation": "const*"},
|
{"name": "data layout", "type": "texture data layout", "annotation": "const*"},
|
||||||
{"name": "write size", "type": "extent 3D", "annotation": "const*"}
|
{"name": "write size", "type": "extent 3D", "annotation": "const*"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "copy texture for browser",
|
||||||
|
"args": [
|
||||||
|
{"name": "source", "type": "texture copy view", "annotation": "const*"},
|
||||||
|
{"name": "destination", "type": "texture copy view", "annotation": "const*"},
|
||||||
|
{"name": "copy size", "type": "extent 3D", "annotation": "const*"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -183,6 +183,8 @@ source_set("dawn_native_sources") {
|
||||||
"ComputePassEncoder.h",
|
"ComputePassEncoder.h",
|
||||||
"ComputePipeline.cpp",
|
"ComputePipeline.cpp",
|
||||||
"ComputePipeline.h",
|
"ComputePipeline.h",
|
||||||
|
"CopyTextureForBrowserHelper.cpp",
|
||||||
|
"CopyTextureForBrowserHelper.h",
|
||||||
"CreateReadyPipelineTracker.cpp",
|
"CreateReadyPipelineTracker.cpp",
|
||||||
"CreateReadyPipelineTracker.h",
|
"CreateReadyPipelineTracker.h",
|
||||||
"Device.cpp",
|
"Device.cpp",
|
||||||
|
@ -213,6 +215,7 @@ source_set("dawn_native_sources") {
|
||||||
"Instance.cpp",
|
"Instance.cpp",
|
||||||
"Instance.h",
|
"Instance.h",
|
||||||
"IntegerTypes.h",
|
"IntegerTypes.h",
|
||||||
|
"InternalPipelineStore.h",
|
||||||
"ObjectBase.cpp",
|
"ObjectBase.cpp",
|
||||||
"ObjectBase.h",
|
"ObjectBase.h",
|
||||||
"PassResourceUsage.h",
|
"PassResourceUsage.h",
|
||||||
|
|
|
@ -70,6 +70,8 @@ target_sources(dawn_native PRIVATE
|
||||||
"ComputePassEncoder.h"
|
"ComputePassEncoder.h"
|
||||||
"ComputePipeline.cpp"
|
"ComputePipeline.cpp"
|
||||||
"ComputePipeline.h"
|
"ComputePipeline.h"
|
||||||
|
"CopyTextureForBrowserHelper.cpp"
|
||||||
|
"CopyTextureForBrowserHelper.h"
|
||||||
"CreateReadyPipelineTracker.cpp"
|
"CreateReadyPipelineTracker.cpp"
|
||||||
"CreateReadyPipelineTracker.h"
|
"CreateReadyPipelineTracker.h"
|
||||||
"Device.cpp"
|
"Device.cpp"
|
||||||
|
@ -99,6 +101,7 @@ target_sources(dawn_native PRIVATE
|
||||||
"Forward.h"
|
"Forward.h"
|
||||||
"Instance.cpp"
|
"Instance.cpp"
|
||||||
"Instance.h"
|
"Instance.h"
|
||||||
|
"InternalPipelineStore.h"
|
||||||
"IntegerTypes.h"
|
"IntegerTypes.h"
|
||||||
"ObjectBase.cpp"
|
"ObjectBase.cpp"
|
||||||
"ObjectBase.h"
|
"ObjectBase.h"
|
||||||
|
|
|
@ -66,41 +66,6 @@ namespace dawn_native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ValidateTextureToTextureCopyRestrictions(const TextureCopyView& src,
|
|
||||||
const TextureCopyView& dst,
|
|
||||||
const Extent3D& copySize) {
|
|
||||||
const uint32_t srcSamples = src.texture->GetSampleCount();
|
|
||||||
const uint32_t dstSamples = dst.texture->GetSampleCount();
|
|
||||||
|
|
||||||
if (srcSamples != dstSamples) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Source and destination textures must have matching sample counts.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src.texture->GetFormat().format != dst.texture->GetFormat().format) {
|
|
||||||
// Metal requires texture-to-texture copies be the same format
|
|
||||||
return DAWN_VALIDATION_ERROR("Source and destination texture formats must match.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src.aspect != wgpu::TextureAspect::All || dst.aspect != wgpu::TextureAspect::All) {
|
|
||||||
// Metal cannot select a single aspect for texture-to-texture copies
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Texture aspect must be \"all\" for texture to texture copies");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src.texture == dst.texture && src.mipLevel == dst.mipLevel) {
|
|
||||||
ASSERT(src.texture->GetDimension() == wgpu::TextureDimension::e2D &&
|
|
||||||
dst.texture->GetDimension() == wgpu::TextureDimension::e2D);
|
|
||||||
if (IsRangeOverlapped(src.origin.z, dst.origin.z, copySize.depth)) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Copy subresources cannot be overlapped when copying within the same "
|
|
||||||
"texture.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateLinearTextureCopyOffset(const TextureDataLayout& layout,
|
MaybeError ValidateLinearTextureCopyOffset(const TextureDataLayout& layout,
|
||||||
const TexelBlockInfo& blockInfo) {
|
const TexelBlockInfo& blockInfo) {
|
||||||
if (layout.offset % blockInfo.byteSize != 0) {
|
if (layout.offset % blockInfo.byteSize != 0) {
|
||||||
|
@ -132,24 +97,6 @@ namespace dawn_native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
|
|
||||||
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
|
||||||
if (!(buffer->GetUsage() & usage)) {
|
|
||||||
return DAWN_VALIDATION_ERROR("buffer doesn't have the required usage.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) {
|
|
||||||
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
|
||||||
if (!(texture->GetUsage() & usage)) {
|
|
||||||
return DAWN_VALIDATION_ERROR("texture doesn't have the required usage.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase* attachment) {
|
MaybeError ValidateAttachmentArrayLayersAndLevelCount(const TextureViewBase* attachment) {
|
||||||
// Currently we do not support layered rendering.
|
// Currently we do not support layered rendering.
|
||||||
if (attachment->GetLayerCount() > 1) {
|
if (attachment->GetLayerCount() > 1) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace dawn_native {
|
||||||
uint64_t destinationOffset);
|
uint64_t destinationOffset);
|
||||||
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
|
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
|
||||||
|
|
||||||
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor);
|
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MaybeError ValidateFinish(CommandIterator* commands,
|
MaybeError ValidateFinish(CommandIterator* commands,
|
||||||
|
|
|
@ -616,4 +616,57 @@ namespace dawn_native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateTextureToTextureCopyRestrictions(const TextureCopyView& src,
|
||||||
|
const TextureCopyView& dst,
|
||||||
|
const Extent3D& copySize) {
|
||||||
|
const uint32_t srcSamples = src.texture->GetSampleCount();
|
||||||
|
const uint32_t dstSamples = dst.texture->GetSampleCount();
|
||||||
|
|
||||||
|
if (srcSamples != dstSamples) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Source and destination textures must have matching sample counts.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.texture->GetFormat().format != dst.texture->GetFormat().format) {
|
||||||
|
// Metal requires texture-to-texture copies be the same format
|
||||||
|
return DAWN_VALIDATION_ERROR("Source and destination texture formats must match.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.aspect != wgpu::TextureAspect::All || dst.aspect != wgpu::TextureAspect::All) {
|
||||||
|
// Metal cannot select a single aspect for texture-to-texture copies
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Texture aspect must be \"all\" for texture to texture copies");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.texture == dst.texture && src.mipLevel == dst.mipLevel) {
|
||||||
|
ASSERT(src.texture->GetDimension() == wgpu::TextureDimension::e2D &&
|
||||||
|
dst.texture->GetDimension() == wgpu::TextureDimension::e2D);
|
||||||
|
if (IsRangeOverlapped(src.origin.z, dst.origin.z, copySize.depth)) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Copy subresources cannot be overlapped when copying within the same "
|
||||||
|
"texture.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage) {
|
||||||
|
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
||||||
|
if (!(texture->GetUsage() & usage)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("texture doesn't have the required usage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
|
||||||
|
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
||||||
|
if (!(buffer->GetUsage() & usage)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("buffer doesn't have the required usage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
|
@ -78,6 +78,14 @@ namespace dawn_native {
|
||||||
|
|
||||||
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
|
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
|
||||||
|
|
||||||
|
MaybeError ValidateTextureToTextureCopyRestrictions(const TextureCopyView& src,
|
||||||
|
const TextureCopyView& dst,
|
||||||
|
const Extent3D& copySize);
|
||||||
|
|
||||||
|
MaybeError ValidateCanUseAs(const TextureBase* texture, wgpu::TextureUsage usage);
|
||||||
|
|
||||||
|
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage);
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
||||||
#endif // DAWNNATIVE_COMMANDVALIDATION_H_
|
#endif // DAWNNATIVE_COMMANDVALIDATION_H_
|
||||||
|
|
|
@ -0,0 +1,307 @@
|
||||||
|
// 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/CopyTextureForBrowserHelper.h"
|
||||||
|
|
||||||
|
#include "dawn_native/BindGroup.h"
|
||||||
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
|
#include "dawn_native/Buffer.h"
|
||||||
|
#include "dawn_native/CommandBuffer.h"
|
||||||
|
#include "dawn_native/CommandEncoder.h"
|
||||||
|
#include "dawn_native/CommandValidation.h"
|
||||||
|
#include "dawn_native/Device.h"
|
||||||
|
#include "dawn_native/InternalPipelineStore.h"
|
||||||
|
#include "dawn_native/Queue.h"
|
||||||
|
#include "dawn_native/RenderPassEncoder.h"
|
||||||
|
#include "dawn_native/RenderPipeline.h"
|
||||||
|
#include "dawn_native/Sampler.h"
|
||||||
|
#include "dawn_native/Texture.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace dawn_native {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// TODO(shaobo.yan@intel.com): Use ANGLE's strategy(render a large triangle) to handle
|
||||||
|
// transform and border interop issue.
|
||||||
|
static const char sCopyTextureForBrowserVertex[] = R"(
|
||||||
|
[[block]] struct Uniforms {
|
||||||
|
[[offset(0)]] rotation : mat4x4<f32>;
|
||||||
|
};
|
||||||
|
const pos : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
|
||||||
|
vec2<f32>(1.0, 1.0),
|
||||||
|
vec2<f32>(1.0, -1.0),
|
||||||
|
vec2<f32>(-1.0, -1.0),
|
||||||
|
vec2<f32>(1.0, 1.0),
|
||||||
|
vec2<f32>(-1.0, -1.0),
|
||||||
|
vec2<f32>(-1.0, 1.0));
|
||||||
|
|
||||||
|
const texUV : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
|
||||||
|
vec2<f32>(1.0, 0.0),
|
||||||
|
vec2<f32>(1.0, 1.0),
|
||||||
|
vec2<f32>(0.0, 1.0),
|
||||||
|
vec2<f32>(1.0, 0.0),
|
||||||
|
vec2<f32>(0.0, 1.0),
|
||||||
|
vec2<f32>(0.0, 0.0));
|
||||||
|
|
||||||
|
[[location(0)]] var<out> texCoord: vec2<f32>;
|
||||||
|
[[builtin(position)]] var<out> Position : vec4<f32>;
|
||||||
|
[[builtin(vertex_idx)]] var<in> VertexIndex : i32;
|
||||||
|
[[binding(0), set(0)]] var<uniform> uniforms : Uniforms;
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn main() -> void {
|
||||||
|
Position = uniforms.rotation * vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||||
|
texCoord = texUV[VertexIndex];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char sPassthrough2D4ChannelFrag[] = R"(
|
||||||
|
[[binding(1), set(0)]] var<uniform_constant> mySampler: sampler;
|
||||||
|
[[binding(2), set(0)]] var<uniform_constant> myTexture: texture_sampled_2d<f32>;
|
||||||
|
[[location(0)]] var<in> texCoord : vec2<f32>;
|
||||||
|
[[location(0)]] var<out> rgbaColor : vec4<f32>;
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn main() -> void {
|
||||||
|
rgbaColor = textureSample(myTexture, mySampler, texCoord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
// TODO(shaobo.yan@intel.com): Expand supported texture formats
|
||||||
|
MaybeError ValidateCopyTextureFormatConversion(const wgpu::TextureFormat srcFormat,
|
||||||
|
const wgpu::TextureFormat dstFormat) {
|
||||||
|
switch (srcFormat) {
|
||||||
|
case wgpu::TextureFormat::RGBA8Unorm:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Unsupported src texture format for CopyTextureForBrowser.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dstFormat) {
|
||||||
|
case wgpu::TextureFormat::RGBA8Unorm:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Unsupported dst texture format for CopyTextureForBrowser.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderPipelineBase* GetOrCreateCopyTextureForBrowserPipeline(DeviceBase* device) {
|
||||||
|
InternalPipelineStore* store = device->GetInternalPipelineStore();
|
||||||
|
|
||||||
|
if (store->copyTextureForBrowserPipeline == nullptr) {
|
||||||
|
// Create vertex shader module if not cached before.
|
||||||
|
if (store->copyTextureForBrowserVS == nullptr) {
|
||||||
|
ShaderModuleDescriptor descriptor;
|
||||||
|
ShaderModuleWGSLDescriptor wgslDesc;
|
||||||
|
wgslDesc.source = sCopyTextureForBrowserVertex;
|
||||||
|
descriptor.nextInChain = reinterpret_cast<ChainedStruct*>(&wgslDesc);
|
||||||
|
|
||||||
|
store->copyTextureForBrowserVS =
|
||||||
|
AcquireRef(device->CreateShaderModule(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderModuleBase* vertexModule = store->copyTextureForBrowserVS.Get();
|
||||||
|
|
||||||
|
// Create fragment shader module if not cached before.
|
||||||
|
if (store->copyTextureForBrowserFS == nullptr) {
|
||||||
|
ShaderModuleDescriptor descriptor;
|
||||||
|
ShaderModuleWGSLDescriptor wgslDesc;
|
||||||
|
wgslDesc.source = sPassthrough2D4ChannelFrag;
|
||||||
|
descriptor.nextInChain = reinterpret_cast<ChainedStruct*>(&wgslDesc);
|
||||||
|
store->copyTextureForBrowserFS =
|
||||||
|
AcquireRef(device->CreateShaderModule(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderModuleBase* fragmentModule = store->copyTextureForBrowserFS.Get();
|
||||||
|
|
||||||
|
// Prepare vertex stage.
|
||||||
|
ProgrammableStageDescriptor vertexStage = {};
|
||||||
|
vertexStage.module = vertexModule;
|
||||||
|
vertexStage.entryPoint = "main";
|
||||||
|
|
||||||
|
// Prepare frgament stage.
|
||||||
|
ProgrammableStageDescriptor fragmentStage = {};
|
||||||
|
fragmentStage.module = fragmentModule;
|
||||||
|
fragmentStage.entryPoint = "main";
|
||||||
|
|
||||||
|
// Prepare color state.
|
||||||
|
ColorStateDescriptor colorState = {};
|
||||||
|
colorState.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
|
||||||
|
// Create RenderPipeline.
|
||||||
|
RenderPipelineDescriptor renderPipelineDesc = {};
|
||||||
|
|
||||||
|
// Generate the layout based on shader modules.
|
||||||
|
renderPipelineDesc.layout = nullptr;
|
||||||
|
|
||||||
|
renderPipelineDesc.vertexStage = vertexStage;
|
||||||
|
renderPipelineDesc.fragmentStage = &fragmentStage;
|
||||||
|
|
||||||
|
renderPipelineDesc.primitiveTopology = wgpu::PrimitiveTopology::TriangleList;
|
||||||
|
|
||||||
|
renderPipelineDesc.colorStateCount = 1;
|
||||||
|
renderPipelineDesc.colorStates = &colorState;
|
||||||
|
|
||||||
|
store->copyTextureForBrowserPipeline =
|
||||||
|
AcquireRef(device->CreateRenderPipeline(&renderPipelineDesc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return store->copyTextureForBrowserPipeline.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
|
||||||
|
const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize) {
|
||||||
|
DAWN_TRY(device->ValidateObject(source->texture));
|
||||||
|
DAWN_TRY(device->ValidateObject(destination->texture));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateTextureCopyView(device, *source, *copySize));
|
||||||
|
DAWN_TRY(ValidateTextureCopyView(device, *destination, *copySize));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
|
||||||
|
DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateCopyTextureFormatConversion(source->texture->GetFormat().format,
|
||||||
|
destination->texture->GetFormat().format));
|
||||||
|
|
||||||
|
// TODO(shaobo.yan@intel.com): Support the simplest case for now that source and destination
|
||||||
|
// texture has the same size and do full texture blit. Will address sub texture blit in
|
||||||
|
// future and remove these validations.
|
||||||
|
if (source->origin.x != 0 || source->origin.y != 0 || source->origin.z != 0 ||
|
||||||
|
destination->origin.x != 0 || destination->origin.y != 0 ||
|
||||||
|
destination->origin.z != 0 || source->mipLevel != 0 || destination->mipLevel != 0 ||
|
||||||
|
source->texture->GetWidth() != destination->texture->GetWidth() ||
|
||||||
|
source->texture->GetHeight() != destination->texture->GetHeight()) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Cannot support sub blit now.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError DoCopyTextureForBrowser(DeviceBase* device,
|
||||||
|
const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize) {
|
||||||
|
// TODO(shaobo.yan@intel.com): In D3D12 and Vulkan, compatible texture format can directly
|
||||||
|
// copy to each other. This can be a potential fast path.
|
||||||
|
RenderPipelineBase* pipeline = GetOrCreateCopyTextureForBrowserPipeline(device);
|
||||||
|
|
||||||
|
// Prepare bind group layout.
|
||||||
|
Ref<BindGroupLayoutBase> layout = AcquireRef(pipeline->GetBindGroupLayout(0));
|
||||||
|
|
||||||
|
// Prepare bind group descriptor
|
||||||
|
BindGroupEntry bindGroupEntries[3] = {};
|
||||||
|
BindGroupDescriptor bgDesc = {};
|
||||||
|
bgDesc.layout = layout.Get();
|
||||||
|
bgDesc.entryCount = 3;
|
||||||
|
bgDesc.entries = bindGroupEntries;
|
||||||
|
|
||||||
|
// Prepare binding 0 resource: uniform buffer.
|
||||||
|
// TODO(shaobo.yan@intel.com): Will use scale vector and offset vector to replace the
|
||||||
|
// 4x4 rotation matrix here.
|
||||||
|
const float rotationMatrix[] = {
|
||||||
|
1.0, 0.0, 0.0, 0.0, //
|
||||||
|
0.0, 1.0, 0.0, 0.0, //
|
||||||
|
0.0, 0.0, 1.0, 0.0, //
|
||||||
|
0.0, 0.0, 0.0, 1.0, //
|
||||||
|
};
|
||||||
|
|
||||||
|
BufferDescriptor rotationUniformDesc = {};
|
||||||
|
rotationUniformDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
|
||||||
|
rotationUniformDesc.size = sizeof(rotationMatrix);
|
||||||
|
Ref<BufferBase> rotationUniform = AcquireRef(device->CreateBuffer(&rotationUniformDesc));
|
||||||
|
|
||||||
|
device->GetDefaultQueue()->WriteBuffer(rotationUniform.Get(), 0, rotationMatrix,
|
||||||
|
sizeof(rotationMatrix));
|
||||||
|
|
||||||
|
// Prepare binding 1 resource: sampler
|
||||||
|
// Use default configuration, filterMode set to Nearest for min and mag.
|
||||||
|
SamplerDescriptor samplerDesc = {};
|
||||||
|
Ref<SamplerBase> sampler = AcquireRef(device->CreateSampler(&samplerDesc));
|
||||||
|
|
||||||
|
// Prepare binding 2 resource: sampled texture
|
||||||
|
TextureViewDescriptor srcTextureViewDesc = {};
|
||||||
|
srcTextureViewDesc.baseMipLevel = source->mipLevel;
|
||||||
|
srcTextureViewDesc.mipLevelCount = 1;
|
||||||
|
Ref<TextureViewBase> srcTextureView =
|
||||||
|
AcquireRef(source->texture->CreateView(&srcTextureViewDesc));
|
||||||
|
|
||||||
|
// Set bind group entries.
|
||||||
|
bindGroupEntries[0].binding = 0;
|
||||||
|
bindGroupEntries[0].buffer = rotationUniform.Get();
|
||||||
|
bindGroupEntries[0].size = sizeof(rotationMatrix);
|
||||||
|
bindGroupEntries[1].binding = 1;
|
||||||
|
bindGroupEntries[1].sampler = sampler.Get();
|
||||||
|
bindGroupEntries[2].binding = 2;
|
||||||
|
bindGroupEntries[2].textureView = srcTextureView.Get();
|
||||||
|
|
||||||
|
// Create bind group after all binding entries are set.
|
||||||
|
Ref<BindGroupBase> bindGroup = AcquireRef(device->CreateBindGroup(&bgDesc));
|
||||||
|
|
||||||
|
// Create command encoder.
|
||||||
|
CommandEncoderDescriptor encoderDesc = {};
|
||||||
|
Ref<CommandEncoder> encoder = AcquireRef(device->CreateCommandEncoder(&encoderDesc));
|
||||||
|
|
||||||
|
// Prepare dst texture view as color Attachment.
|
||||||
|
TextureViewDescriptor dstTextureViewDesc;
|
||||||
|
dstTextureViewDesc.baseMipLevel = destination->mipLevel;
|
||||||
|
dstTextureViewDesc.mipLevelCount = 1;
|
||||||
|
Ref<TextureViewBase> dstView =
|
||||||
|
AcquireRef(destination->texture->CreateView(&dstTextureViewDesc));
|
||||||
|
|
||||||
|
// Prepare render pass color attachment descriptor.
|
||||||
|
RenderPassColorAttachmentDescriptor colorAttachmentDesc;
|
||||||
|
colorAttachmentDesc.attachment = dstView.Get();
|
||||||
|
colorAttachmentDesc.loadOp = wgpu::LoadOp::Load;
|
||||||
|
colorAttachmentDesc.storeOp = wgpu::StoreOp::Store;
|
||||||
|
colorAttachmentDesc.clearColor = {0.0, 0.0, 0.0, 1.0};
|
||||||
|
|
||||||
|
// Create render pass.
|
||||||
|
RenderPassDescriptor renderPassDesc;
|
||||||
|
renderPassDesc.colorAttachmentCount = 1;
|
||||||
|
renderPassDesc.colorAttachments = &colorAttachmentDesc;
|
||||||
|
Ref<RenderPassEncoder> passEncoder = AcquireRef(encoder->BeginRenderPass(&renderPassDesc));
|
||||||
|
|
||||||
|
// Start pipeline and encode commands to complete
|
||||||
|
// the copy from src texture to dst texture with transformation.
|
||||||
|
passEncoder->SetPipeline(pipeline);
|
||||||
|
passEncoder->SetBindGroup(0, bindGroup.Get());
|
||||||
|
passEncoder->Draw(6);
|
||||||
|
passEncoder->EndPass();
|
||||||
|
|
||||||
|
// Finsh encoding.
|
||||||
|
Ref<CommandBufferBase> commandBuffer = AcquireRef(encoder->Finish());
|
||||||
|
CommandBufferBase* submitCommandBuffer = commandBuffer.Get();
|
||||||
|
|
||||||
|
// Submit command buffer.
|
||||||
|
Ref<QueueBase> queue = AcquireRef(device->GetDefaultQueue());
|
||||||
|
queue->Submit(1, &submitCommandBuffer);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dawn_native
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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_COPYTEXTUREFORBROWSERHELPER_H_
|
||||||
|
#define DAWNNATIVE_COPYTEXTUREFORBROWSERHELPER_H_
|
||||||
|
|
||||||
|
#include "dawn_native/Error.h"
|
||||||
|
#include "dawn_native/ObjectBase.h"
|
||||||
|
|
||||||
|
namespace dawn_native {
|
||||||
|
class DeviceBase;
|
||||||
|
struct Extent3D;
|
||||||
|
struct TextureCopyView;
|
||||||
|
|
||||||
|
MaybeError ValidateCopyTextureForBrowser(DeviceBase* device,
|
||||||
|
const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize);
|
||||||
|
|
||||||
|
MaybeError DoCopyTextureForBrowser(DeviceBase* device,
|
||||||
|
const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize);
|
||||||
|
|
||||||
|
} // namespace dawn_native
|
||||||
|
|
||||||
|
#endif // DAWNNATIVE_COPYTEXTUREFORBROWSERHELPER_H_
|
|
@ -30,6 +30,7 @@
|
||||||
#include "dawn_native/ErrorScopeTracker.h"
|
#include "dawn_native/ErrorScopeTracker.h"
|
||||||
#include "dawn_native/Fence.h"
|
#include "dawn_native/Fence.h"
|
||||||
#include "dawn_native/Instance.h"
|
#include "dawn_native/Instance.h"
|
||||||
|
#include "dawn_native/InternalPipelineStore.h"
|
||||||
#include "dawn_native/PipelineLayout.h"
|
#include "dawn_native/PipelineLayout.h"
|
||||||
#include "dawn_native/QuerySet.h"
|
#include "dawn_native/QuerySet.h"
|
||||||
#include "dawn_native/Queue.h"
|
#include "dawn_native/Queue.h"
|
||||||
|
@ -105,6 +106,7 @@ namespace dawn_native {
|
||||||
mDynamicUploader = std::make_unique<DynamicUploader>(this);
|
mDynamicUploader = std::make_unique<DynamicUploader>(this);
|
||||||
mCreateReadyPipelineTracker = std::make_unique<CreateReadyPipelineTracker>(this);
|
mCreateReadyPipelineTracker = std::make_unique<CreateReadyPipelineTracker>(this);
|
||||||
mDeprecationWarnings = std::make_unique<DeprecationWarnings>();
|
mDeprecationWarnings = std::make_unique<DeprecationWarnings>();
|
||||||
|
mInternalPipelineStore = std::make_unique<InternalPipelineStore>();
|
||||||
|
|
||||||
// Starting from now the backend can start doing reentrant calls so the device is marked as
|
// Starting from now the backend can start doing reentrant calls so the device is marked as
|
||||||
// alive.
|
// alive.
|
||||||
|
@ -172,6 +174,8 @@ namespace dawn_native {
|
||||||
|
|
||||||
mEmptyBindGroupLayout = nullptr;
|
mEmptyBindGroupLayout = nullptr;
|
||||||
|
|
||||||
|
mInternalPipelineStore = nullptr;
|
||||||
|
|
||||||
AssumeCommandsComplete();
|
AssumeCommandsComplete();
|
||||||
// Tell the backend that it can free all the objects now that the GPU timeline is empty.
|
// Tell the backend that it can free all the objects now that the GPU timeline is empty.
|
||||||
ShutDownImpl();
|
ShutDownImpl();
|
||||||
|
@ -329,6 +333,10 @@ namespace dawn_native {
|
||||||
return mFutureSerial;
|
return mFutureSerial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InternalPipelineStore* DeviceBase::GetInternalPipelineStore() {
|
||||||
|
return mInternalPipelineStore.get();
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceBase::IncrementLastSubmittedCommandSerial() {
|
void DeviceBase::IncrementLastSubmittedCommandSerial() {
|
||||||
mLastSubmittedSerial++;
|
mLastSubmittedSerial++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace dawn_native {
|
||||||
class ErrorScope;
|
class ErrorScope;
|
||||||
class ErrorScopeTracker;
|
class ErrorScopeTracker;
|
||||||
class StagingBufferBase;
|
class StagingBufferBase;
|
||||||
|
struct InternalPipelineStore;
|
||||||
|
|
||||||
class DeviceBase {
|
class DeviceBase {
|
||||||
public:
|
public:
|
||||||
|
@ -161,6 +162,7 @@ namespace dawn_native {
|
||||||
TextureBase* CreateTexture(const TextureDescriptor* descriptor);
|
TextureBase* CreateTexture(const TextureDescriptor* descriptor);
|
||||||
TextureViewBase* CreateTextureView(TextureBase* texture,
|
TextureViewBase* CreateTextureView(TextureBase* texture,
|
||||||
const TextureViewDescriptor* descriptor);
|
const TextureViewDescriptor* descriptor);
|
||||||
|
InternalPipelineStore* GetInternalPipelineStore();
|
||||||
|
|
||||||
// For Dawn Wire
|
// For Dawn Wire
|
||||||
BufferBase* CreateErrorBuffer();
|
BufferBase* CreateErrorBuffer();
|
||||||
|
@ -385,6 +387,8 @@ namespace dawn_native {
|
||||||
size_t mLazyClearCountForTesting = 0;
|
size_t mLazyClearCountForTesting = 0;
|
||||||
|
|
||||||
ExtensionsSet mEnabledExtensions;
|
ExtensionsSet mEnabledExtensions;
|
||||||
|
|
||||||
|
std::unique_ptr<InternalPipelineStore> mInternalPipelineStore;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
|
@ -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_INTERNALPIPELINESTORE_H_
|
||||||
|
#define DAWNNATIVE_INTERNALPIPELINESTORE_H_
|
||||||
|
|
||||||
|
#include "dawn_native/ObjectBase.h"
|
||||||
|
#include "dawn_native/dawn_platform.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace dawn_native {
|
||||||
|
class RenderPipelineBase;
|
||||||
|
class ShaderModuleBase;
|
||||||
|
|
||||||
|
struct InternalPipelineStore {
|
||||||
|
Ref<RenderPipelineBase> copyTextureForBrowserPipeline;
|
||||||
|
Ref<ShaderModuleBase> copyTextureForBrowserVS;
|
||||||
|
Ref<ShaderModuleBase> copyTextureForBrowserFS;
|
||||||
|
};
|
||||||
|
} // namespace dawn_native
|
||||||
|
|
||||||
|
#endif // DAWNNATIVE_INTERNALPIPELINESTORE_H_
|
|
@ -40,8 +40,8 @@ namespace dawn_native {
|
||||||
|
|
||||||
void SetBindGroup(uint32_t groupIndex,
|
void SetBindGroup(uint32_t groupIndex,
|
||||||
BindGroupBase* group,
|
BindGroupBase* group,
|
||||||
uint32_t dynamicOffsetCount,
|
uint32_t dynamicOffsetCount = 0,
|
||||||
const uint32_t* dynamicOffsets);
|
const uint32_t* dynamicOffsets = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Construct an "error" programmable pass encoder.
|
// Construct an "error" programmable pass encoder.
|
||||||
|
|
|
@ -17,14 +17,18 @@
|
||||||
#include "common/Constants.h"
|
#include "common/Constants.h"
|
||||||
#include "dawn_native/Buffer.h"
|
#include "dawn_native/Buffer.h"
|
||||||
#include "dawn_native/CommandBuffer.h"
|
#include "dawn_native/CommandBuffer.h"
|
||||||
|
#include "dawn_native/CommandEncoder.h"
|
||||||
#include "dawn_native/CommandValidation.h"
|
#include "dawn_native/CommandValidation.h"
|
||||||
#include "dawn_native/Commands.h"
|
#include "dawn_native/Commands.h"
|
||||||
|
#include "dawn_native/CopyTextureForBrowserHelper.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/DynamicUploader.h"
|
#include "dawn_native/DynamicUploader.h"
|
||||||
#include "dawn_native/ErrorScope.h"
|
#include "dawn_native/ErrorScope.h"
|
||||||
#include "dawn_native/ErrorScopeTracker.h"
|
#include "dawn_native/ErrorScopeTracker.h"
|
||||||
#include "dawn_native/Fence.h"
|
#include "dawn_native/Fence.h"
|
||||||
#include "dawn_native/QuerySet.h"
|
#include "dawn_native/QuerySet.h"
|
||||||
|
#include "dawn_native/RenderPassEncoder.h"
|
||||||
|
#include "dawn_native/RenderPipeline.h"
|
||||||
#include "dawn_native/Texture.h"
|
#include "dawn_native/Texture.h"
|
||||||
#include "dawn_platform/DawnPlatform.h"
|
#include "dawn_platform/DawnPlatform.h"
|
||||||
#include "dawn_platform/tracing/TraceEvent.h"
|
#include "dawn_platform/tracing/TraceEvent.h"
|
||||||
|
@ -131,7 +135,6 @@ namespace dawn_native {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// QueueBase
|
// QueueBase
|
||||||
|
@ -306,6 +309,23 @@ namespace dawn_native {
|
||||||
return device->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout,
|
return device->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout,
|
||||||
&textureCopy, writeSizePixel);
|
&textureCopy, writeSizePixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QueueBase::CopyTextureForBrowser(const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize) {
|
||||||
|
GetDevice()->ConsumedError(CopyTextureForBrowserInternal(source, destination, copySize));
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError QueueBase::CopyTextureForBrowserInternal(const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize) {
|
||||||
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateCopyTextureForBrowser(GetDevice(), source, destination, copySize));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoCopyTextureForBrowser(GetDevice(), source, destination, copySize);
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
|
MaybeError QueueBase::ValidateSubmit(uint32_t commandCount,
|
||||||
CommandBufferBase* const* commands) const {
|
CommandBufferBase* const* commands) const {
|
||||||
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "Queue::ValidateSubmit");
|
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "Queue::ValidateSubmit");
|
||||||
|
|
|
@ -45,6 +45,9 @@ namespace dawn_native {
|
||||||
size_t dataSize,
|
size_t dataSize,
|
||||||
const TextureDataLayout* dataLayout,
|
const TextureDataLayout* dataLayout,
|
||||||
const Extent3D* writeSize);
|
const Extent3D* writeSize);
|
||||||
|
void CopyTextureForBrowser(const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize);
|
||||||
|
|
||||||
void TrackTask(std::unique_ptr<TaskInFlight> task, ExecutionSerial serial);
|
void TrackTask(std::unique_ptr<TaskInFlight> task, ExecutionSerial serial);
|
||||||
void Tick(ExecutionSerial finishedSerial);
|
void Tick(ExecutionSerial finishedSerial);
|
||||||
|
@ -63,6 +66,9 @@ namespace dawn_native {
|
||||||
size_t dataSize,
|
size_t dataSize,
|
||||||
const TextureDataLayout* dataLayout,
|
const TextureDataLayout* dataLayout,
|
||||||
const Extent3D* writeSize);
|
const Extent3D* writeSize);
|
||||||
|
MaybeError CopyTextureForBrowserInternal(const TextureCopyView* source,
|
||||||
|
const TextureCopyView* destination,
|
||||||
|
const Extent3D* copySize);
|
||||||
|
|
||||||
virtual MaybeError SubmitImpl(uint32_t commandCount,
|
virtual MaybeError SubmitImpl(uint32_t commandCount,
|
||||||
CommandBufferBase* const* commands) = 0;
|
CommandBufferBase* const* commands) = 0;
|
||||||
|
|
|
@ -25,9 +25,9 @@ namespace dawn_native {
|
||||||
RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext);
|
RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext);
|
||||||
|
|
||||||
void Draw(uint32_t vertexCount,
|
void Draw(uint32_t vertexCount,
|
||||||
uint32_t instanceCount,
|
uint32_t instanceCount = 1,
|
||||||
uint32_t firstVertex,
|
uint32_t firstVertex = 0,
|
||||||
uint32_t firstInstance);
|
uint32_t firstInstance = 0);
|
||||||
void DrawIndexed(uint32_t vertexCount,
|
void DrawIndexed(uint32_t vertexCount,
|
||||||
uint32_t instanceCount,
|
uint32_t instanceCount,
|
||||||
uint32_t firstIndex,
|
uint32_t firstIndex,
|
||||||
|
|
|
@ -275,6 +275,7 @@ source_set("dawn_end2end_tests_sources") {
|
||||||
"end2end/ComputeSharedMemoryTests.cpp",
|
"end2end/ComputeSharedMemoryTests.cpp",
|
||||||
"end2end/ComputeStorageBufferBarrierTests.cpp",
|
"end2end/ComputeStorageBufferBarrierTests.cpp",
|
||||||
"end2end/CopyTests.cpp",
|
"end2end/CopyTests.cpp",
|
||||||
|
"end2end/CopyTextureForBrowserTests.cpp",
|
||||||
"end2end/CreateReadyPipelineTests.cpp",
|
"end2end/CreateReadyPipelineTests.cpp",
|
||||||
"end2end/CullingTests.cpp",
|
"end2end/CullingTests.cpp",
|
||||||
"end2end/DebugMarkerTests.cpp",
|
"end2end/DebugMarkerTests.cpp",
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
// 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 "tests/DawnTest.h"
|
||||||
|
|
||||||
|
#include "common/Constants.h"
|
||||||
|
#include "common/Math.h"
|
||||||
|
#include "utils/TestUtils.h"
|
||||||
|
#include "utils/TextureFormatUtils.h"
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
|
class CopyTextureForBrowserTests : public DawnTest {
|
||||||
|
protected:
|
||||||
|
static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
|
||||||
|
struct TextureSpec {
|
||||||
|
wgpu::Origin3D copyOrigin;
|
||||||
|
wgpu::Extent3D textureSize;
|
||||||
|
uint32_t level;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<RGBA8> GetExpectedTextureData(const utils::TextureDataCopyLayout& layout) {
|
||||||
|
std::vector<RGBA8> textureData(layout.texelBlockCount);
|
||||||
|
for (uint32_t layer = 0; layer < layout.mipSize.depth; ++layer) {
|
||||||
|
const uint32_t sliceOffset = layout.texelBlocksPerImage * layer;
|
||||||
|
for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
|
||||||
|
const uint32_t rowOffset = layout.texelBlocksPerRow * y;
|
||||||
|
for (uint32_t x = 0; x < layout.mipSize.width; ++x) {
|
||||||
|
textureData[sliceOffset + rowOffset + x] =
|
||||||
|
RGBA8(static_cast<uint8_t>((x + layer * x) % 256),
|
||||||
|
static_cast<uint8_t>((y + layer * y) % 256),
|
||||||
|
static_cast<uint8_t>(x / 256), static_cast<uint8_t>(y / 256));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return textureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PackTextureData(const RGBA8* srcData,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
uint32_t srcTexelsPerRow,
|
||||||
|
RGBA8* dstData,
|
||||||
|
uint32_t dstTexelsPerRow) {
|
||||||
|
for (unsigned int y = 0; y < height; ++y) {
|
||||||
|
for (unsigned int x = 0; x < width; ++x) {
|
||||||
|
unsigned int src = x + y * srcTexelsPerRow;
|
||||||
|
unsigned int dst = x + y * dstTexelsPerRow;
|
||||||
|
dstData[dst] = srcData[src];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoTest(const TextureSpec& srcSpec,
|
||||||
|
const TextureSpec& dstSpec,
|
||||||
|
const wgpu::Extent3D& copySize) {
|
||||||
|
wgpu::TextureDescriptor srcDescriptor;
|
||||||
|
srcDescriptor.size = srcSpec.textureSize;
|
||||||
|
srcDescriptor.format = kTextureFormat;
|
||||||
|
srcDescriptor.mipLevelCount = srcSpec.level + 1;
|
||||||
|
srcDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||||
|
wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
|
||||||
|
wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
|
||||||
|
|
||||||
|
wgpu::Texture dstTexture;
|
||||||
|
wgpu::TextureDescriptor dstDescriptor;
|
||||||
|
dstDescriptor.size = dstSpec.textureSize;
|
||||||
|
dstDescriptor.format = kTextureFormat;
|
||||||
|
dstDescriptor.mipLevelCount = dstSpec.level + 1;
|
||||||
|
dstDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||||
|
wgpu::TextureUsage::OutputAttachment;
|
||||||
|
dstTexture = device.CreateTexture(&dstDescriptor);
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
|
||||||
|
// Use writeTexture to populate the current slice of the texture in
|
||||||
|
// `level` mip level for all platforms except OpenGL.
|
||||||
|
// TODO(shaobo.yan@intel.com): OpenGL doesn't have 'WriteTexture' implementation.
|
||||||
|
const utils::TextureDataCopyLayout copyLayout =
|
||||||
|
utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||||
|
kTextureFormat,
|
||||||
|
{srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth},
|
||||||
|
srcSpec.level, 0);
|
||||||
|
|
||||||
|
const std::vector<RGBA8> textureArrayCopyData = GetExpectedTextureData(copyLayout);
|
||||||
|
wgpu::TextureCopyView textureCopyView =
|
||||||
|
utils::CreateTextureCopyView(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z});
|
||||||
|
|
||||||
|
wgpu::TextureDataLayout textureDataLayout;
|
||||||
|
textureDataLayout.offset = 0;
|
||||||
|
textureDataLayout.bytesPerRow = copyLayout.bytesPerRow;
|
||||||
|
textureDataLayout.rowsPerImage = copyLayout.bytesPerImage / copyLayout.bytesPerRow;
|
||||||
|
|
||||||
|
device.GetDefaultQueue().WriteTexture(&textureCopyView, textureArrayCopyData.data(),
|
||||||
|
textureArrayCopyData.size() * sizeof(RGBA8),
|
||||||
|
&textureDataLayout, ©Layout.mipSize);
|
||||||
|
|
||||||
|
const wgpu::Extent3D copySizePerSlice = {copySize.width, copySize.height, 1};
|
||||||
|
// Perform the texture to texture copy
|
||||||
|
wgpu::TextureCopyView srcTextureCopyView =
|
||||||
|
utils::CreateTextureCopyView(srcTexture, srcSpec.level, srcSpec.copyOrigin);
|
||||||
|
wgpu::TextureCopyView dstTextureCopyView =
|
||||||
|
utils::CreateTextureCopyView(dstTexture, dstSpec.level, dstSpec.copyOrigin);
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
// Perform a copy here for testing.
|
||||||
|
device.GetDefaultQueue().CopyTextureForBrowser(&srcTextureCopyView, &dstTextureCopyView,
|
||||||
|
©Size);
|
||||||
|
|
||||||
|
// Texels in single slice.
|
||||||
|
const uint32_t texelCountInCopyRegion = utils::GetTexelCountInCopyRegion(
|
||||||
|
copyLayout.bytesPerRow, copyLayout.bytesPerImage / copyLayout.bytesPerRow,
|
||||||
|
copySizePerSlice, kTextureFormat);
|
||||||
|
std::vector<RGBA8> expected(texelCountInCopyRegion);
|
||||||
|
for (uint32_t slice = 0; slice < copySize.depth; ++slice) {
|
||||||
|
std::fill(expected.begin(), expected.end(), RGBA8());
|
||||||
|
const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * slice;
|
||||||
|
const uint32_t expectedTexelArrayDataStartIndex =
|
||||||
|
texelIndexOffset +
|
||||||
|
(srcSpec.copyOrigin.x + srcSpec.copyOrigin.y * copyLayout.texelBlocksPerRow);
|
||||||
|
PackTextureData(&textureArrayCopyData[expectedTexelArrayDataStartIndex], copySize.width,
|
||||||
|
copySize.height, copyLayout.texelBlocksPerRow, expected.data(),
|
||||||
|
copySize.width);
|
||||||
|
|
||||||
|
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), dstTexture, dstSpec.copyOrigin.x,
|
||||||
|
dstSpec.copyOrigin.y, copySize.width, copySize.height,
|
||||||
|
dstSpec.level, dstSpec.copyOrigin.z + slice)
|
||||||
|
<< "Texture to Texture copy failed copying region [(" << srcSpec.copyOrigin.x
|
||||||
|
<< ", " << srcSpec.copyOrigin.y << "), (" << srcSpec.copyOrigin.x + copySize.width
|
||||||
|
<< ", " << srcSpec.copyOrigin.y + copySize.height << ")) from "
|
||||||
|
<< srcSpec.textureSize.width << " x " << srcSpec.textureSize.height
|
||||||
|
<< " texture at mip level " << srcSpec.level << " layer "
|
||||||
|
<< srcSpec.copyOrigin.z + slice << " to [(" << dstSpec.copyOrigin.x << ", "
|
||||||
|
<< dstSpec.copyOrigin.y << "), (" << dstSpec.copyOrigin.x + copySize.width << ", "
|
||||||
|
<< dstSpec.copyOrigin.y + copySize.height << ")) region of "
|
||||||
|
<< dstSpec.textureSize.width << " x " << dstSpec.textureSize.height
|
||||||
|
<< " texture at mip level " << dstSpec.level << " layer "
|
||||||
|
<< dstSpec.copyOrigin.z + slice << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify CopyTextureForBrowserTests works with internal pipeline.
|
||||||
|
// The case do copy without any transform.
|
||||||
|
TEST_P(CopyTextureForBrowserTests, PassthroughCopy) {
|
||||||
|
// These tests fails due to crbug.com/tint/63.
|
||||||
|
DAWN_SKIP_TEST_IF(IsSwiftshader());
|
||||||
|
DAWN_SKIP_TEST_IF(IsVulkan());
|
||||||
|
DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
|
||||||
|
|
||||||
|
// OpenGL tests fails due to 'WriteTexture' unimplemented.
|
||||||
|
// Related bug : crbug.com/dawn/483
|
||||||
|
DAWN_SKIP_TEST_IF(IsOpenGL());
|
||||||
|
|
||||||
|
constexpr uint32_t kWidth = 10;
|
||||||
|
constexpr uint32_t kHeight = 1;
|
||||||
|
|
||||||
|
TextureSpec textureSpec;
|
||||||
|
textureSpec.copyOrigin = {0, 0, 0};
|
||||||
|
textureSpec.level = 0;
|
||||||
|
textureSpec.textureSize = {kWidth, kHeight, 1};
|
||||||
|
DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INSTANTIATE_TEST(CopyTextureForBrowserTests,
|
||||||
|
D3D12Backend(),
|
||||||
|
MetalBackend(),
|
||||||
|
OpenGLBackend(),
|
||||||
|
VulkanBackend());
|
Loading…
Reference in New Issue