|  | // 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/EncodingContext.h" | 
|  |  | 
|  | #include "common/Assert.h" | 
|  | #include "dawn_native/CommandEncoder.h" | 
|  | #include "dawn_native/Commands.h" | 
|  | #include "dawn_native/Device.h" | 
|  | #include "dawn_native/ErrorData.h" | 
|  | #include "dawn_native/RenderBundleEncoder.h" | 
|  |  | 
|  | namespace dawn_native { | 
|  |  | 
|  | EncodingContext::EncodingContext(DeviceBase* device, const ObjectBase* initialEncoder) | 
|  | : mDevice(device), mTopLevelEncoder(initialEncoder), mCurrentEncoder(initialEncoder) { | 
|  | } | 
|  |  | 
|  | EncodingContext::~EncodingContext() { | 
|  | if (!mWereCommandsAcquired) { | 
|  | FreeCommands(GetIterator()); | 
|  | } | 
|  | } | 
|  |  | 
|  | CommandIterator EncodingContext::AcquireCommands() { | 
|  | MoveToIterator(); | 
|  | ASSERT(!mWereCommandsAcquired); | 
|  | mWereCommandsAcquired = true; | 
|  | return std::move(mIterator); | 
|  | } | 
|  |  | 
|  | CommandIterator* EncodingContext::GetIterator() { | 
|  | MoveToIterator(); | 
|  | ASSERT(!mWereCommandsAcquired); | 
|  | return &mIterator; | 
|  | } | 
|  |  | 
|  | void EncodingContext::MoveToIterator() { | 
|  | if (!mWasMovedToIterator) { | 
|  | mIterator = std::move(mAllocator); | 
|  | mWasMovedToIterator = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | void EncodingContext::HandleError(InternalErrorType type, const char* message) { | 
|  | if (!IsFinished()) { | 
|  | // If the encoding context is not finished, errors are deferred until | 
|  | // Finish() is called. | 
|  | if (!mGotError) { | 
|  | mGotError = true; | 
|  | mErrorMessage = message; | 
|  | } | 
|  | } else { | 
|  | mDevice->HandleError(type, message); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EncodingContext::EnterPass(const ObjectBase* passEncoder) { | 
|  | // Assert we're at the top level. | 
|  | ASSERT(mCurrentEncoder == mTopLevelEncoder); | 
|  | ASSERT(passEncoder != nullptr); | 
|  |  | 
|  | mCurrentEncoder = passEncoder; | 
|  | } | 
|  |  | 
|  | void EncodingContext::ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsage) { | 
|  | // Assert we're not at the top level. | 
|  | ASSERT(mCurrentEncoder != mTopLevelEncoder); | 
|  | // Assert the pass encoder is current. | 
|  | ASSERT(mCurrentEncoder == passEncoder); | 
|  |  | 
|  | mCurrentEncoder = mTopLevelEncoder; | 
|  | mPassUsages.push_back(std::move(passUsage)); | 
|  | } | 
|  |  | 
|  | const PerPassUsages& EncodingContext::GetPassUsages() const { | 
|  | ASSERT(!mWerePassUsagesAcquired); | 
|  | return mPassUsages; | 
|  | } | 
|  |  | 
|  | PerPassUsages EncodingContext::AcquirePassUsages() { | 
|  | ASSERT(!mWerePassUsagesAcquired); | 
|  | mWerePassUsagesAcquired = true; | 
|  | return std::move(mPassUsages); | 
|  | } | 
|  |  | 
|  | MaybeError EncodingContext::Finish() { | 
|  | if (IsFinished()) { | 
|  | return DAWN_VALIDATION_ERROR("Command encoding already finished"); | 
|  | } | 
|  |  | 
|  | const void* currentEncoder = mCurrentEncoder; | 
|  | const void* topLevelEncoder = mTopLevelEncoder; | 
|  |  | 
|  | // Even if finish validation fails, it is now invalid to call any encoding commands, | 
|  | // so we clear the encoders. Note: mTopLevelEncoder == nullptr is used as a flag for | 
|  | // if Finish() has been called. | 
|  | mCurrentEncoder = nullptr; | 
|  | mTopLevelEncoder = nullptr; | 
|  |  | 
|  | if (mGotError) { | 
|  | return DAWN_VALIDATION_ERROR(mErrorMessage); | 
|  | } | 
|  | if (currentEncoder != topLevelEncoder) { | 
|  | return DAWN_VALIDATION_ERROR("Command buffer recording ended mid-pass"); | 
|  | } | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | bool EncodingContext::IsFinished() const { | 
|  | return mTopLevelEncoder == nullptr; | 
|  | } | 
|  |  | 
|  | }  // namespace dawn_native |