blob: 23eb14367e145bcee50ec3ce96db85bbad65dabd [file] [log] [blame]
// 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 { namespace 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) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
Texture* texture = ToBackend(destination.texture);
SubresourceRange range(Aspect::Color, {destination.origin.z, writeSizePixel.depth},
{destination.mipLevel, 1});
if (IsCompleteSubresourceCopiedTo(texture, writeSizePixel, destination.mipLevel)) {
texture->SetIsSubresourceContentInitialized(true, range);
} else {
texture->EnsureSubresourceContentInitialized(range);
}
const GLFormat& format = texture->GetGLFormat();
GLenum target = texture->GetGLTarget();
data = static_cast<const uint8_t*>(data) + dataLayout.offset;
gl.BindTexture(target, texture->GetHandle());
const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(destination.aspect).block;
if (texture->GetFormat().isCompressed) {
size_t imageSize = writeSizePixel.width / blockInfo.width * blockInfo.byteSize;
Extent3D virtSize = texture->GetMipLevelVirtualSize(destination.mipLevel);
uint32_t width = std::min(writeSizePixel.width, virtSize.width - destination.origin.x);
uint32_t x = destination.origin.x;
// For now, we use row-by-row texture uploads of compressed textures in all cases.
// TODO(crbug.com/dawn/684): For contiguous cases, we should be able to use a single
// texture upload per layer, as we do in the non-compressed case.
if (texture->GetArrayLayers() == 1) {
const uint8_t* d = static_cast<const uint8_t*>(data);
for (uint32_t y = destination.origin.y;
y < destination.origin.y + writeSizePixel.height; y += blockInfo.height) {
uint32_t height = std::min(blockInfo.height, virtSize.height - y);
gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width, height,
format.internalFormat, imageSize, d);
d += dataLayout.bytesPerRow;
}
} else {
const uint8_t* slice = static_cast<const uint8_t*>(data);
for (uint32_t z = destination.origin.z;
z < destination.origin.z + writeSizePixel.depth; ++z) {
const uint8_t* d = slice;
for (uint32_t y = destination.origin.y;
y < destination.origin.y + writeSizePixel.height; y += blockInfo.height) {
uint32_t height = std::min(blockInfo.height, virtSize.height - y);
gl.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width,
height, 1, format.internalFormat, imageSize, d);
d += dataLayout.bytesPerRow;
}
slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
}
}
} else if (dataLayout.bytesPerRow % blockInfo.byteSize == 0) {
gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width);
if (texture->GetArrayLayers() == 1) {
gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
destination.origin.y, writeSizePixel.width, writeSizePixel.height,
format.format, format.type, data);
} else {
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, dataLayout.rowsPerImage * blockInfo.height);
gl.TexSubImage3D(target, destination.mipLevel, destination.origin.x,
destination.origin.y, destination.origin.z, writeSizePixel.width,
writeSizePixel.height, writeSizePixel.depth, format.format,
format.type, data);
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
}
gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else {
if (texture->GetArrayLayers() == 1) {
const uint8_t* d = static_cast<const uint8_t*>(data);
for (uint32_t y = 0; y < writeSizePixel.height; ++y) {
gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
destination.origin.y + y, writeSizePixel.width, 1,
format.format, format.type, d);
d += dataLayout.bytesPerRow;
}
} else {
const uint8_t* slice = static_cast<const uint8_t*>(data);
for (uint32_t z = 0; z < writeSizePixel.depth; ++z) {
const uint8_t* d = slice;
for (uint32_t y = 0; y < writeSizePixel.height; ++y) {
gl.TexSubImage3D(target, destination.mipLevel, destination.origin.x,
destination.origin.y + y, destination.origin.z + z,
writeSizePixel.width, 1, 1, format.format, format.type, d);
d += dataLayout.bytesPerRow;
}
slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
}
}
}
return {};
}
}} // namespace dawn_native::opengl