Improve validation errors for encoders

Improves the validation messages in ComputePassEncoder.cpp,
ProgrammablePassEncoder.cpp, RenderBundleEncoder.cpp, and
EncodingContext.cpp/h to give them more contextual information.

Bug: dawn:563
Change-Id: I3807c30fb0de8e766fbc35b98ef9c059f9d441ee
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/67603
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/EncodingContext.cpp b/src/dawn_native/EncodingContext.cpp
index 2724291..9122d83 100644
--- a/src/dawn_native/EncodingContext.cpp
+++ b/src/dawn_native/EncodingContext.cpp
@@ -24,7 +24,7 @@
 
 namespace dawn_native {
 
-    EncodingContext::EncodingContext(DeviceBase* device, const ObjectBase* initialEncoder)
+    EncodingContext::EncodingContext(DeviceBase* device, const ApiObjectBase* initialEncoder)
         : mDevice(device), mTopLevelEncoder(initialEncoder), mCurrentEncoder(initialEncoder) {
     }
 
@@ -87,7 +87,7 @@
         }
     }
 
-    void EncodingContext::EnterPass(const ObjectBase* passEncoder) {
+    void EncodingContext::EnterPass(const ApiObjectBase* passEncoder) {
         // Assert we're at the top level.
         ASSERT(mCurrentEncoder == mTopLevelEncoder);
         ASSERT(passEncoder != nullptr);
@@ -95,7 +95,7 @@
         mCurrentEncoder = passEncoder;
     }
 
-    MaybeError EncodingContext::ExitRenderPass(const ObjectBase* passEncoder,
+    MaybeError EncodingContext::ExitRenderPass(const ApiObjectBase* passEncoder,
                                                RenderPassResourceUsageTracker usageTracker,
                                                CommandEncoder* commandEncoder,
                                                IndirectDrawMetadata indirectDrawMetadata) {
@@ -121,7 +121,7 @@
         return {};
     }
 
-    void EncodingContext::ExitComputePass(const ObjectBase* passEncoder,
+    void EncodingContext::ExitComputePass(const ApiObjectBase* passEncoder,
                                           ComputePassResourceUsage usages) {
         ASSERT(mCurrentEncoder != mTopLevelEncoder);
         ASSERT(mCurrentEncoder == passEncoder);
@@ -130,6 +130,15 @@
         mComputePassUsages.push_back(std::move(usages));
     }
 
+    void EncodingContext::EnsurePassExited(const ApiObjectBase* passEncoder) {
+        if (mCurrentEncoder != mTopLevelEncoder && mCurrentEncoder == passEncoder) {
+            // The current pass encoder is being deleted. Implicitly end the pass with an error.
+            mCurrentEncoder = mTopLevelEncoder;
+            HandleError(DAWN_FORMAT_VALIDATION_ERROR(
+                "Command buffer recording ended before %s was ended.", passEncoder));
+        }
+    }
+
     const RenderPassUsages& EncodingContext::GetRenderPassUsages() const {
         ASSERT(!mWereRenderPassUsagesAcquired);
         return mRenderPassUsages;
@@ -161,12 +170,10 @@
     }
 
     MaybeError EncodingContext::Finish() {
-        if (IsFinished()) {
-            return DAWN_VALIDATION_ERROR("Command encoding already finished");
-        }
+        DAWN_INVALID_IF(IsFinished(), "Command encoding already finished.");
 
-        const void* currentEncoder = mCurrentEncoder;
-        const void* topLevelEncoder = mTopLevelEncoder;
+        const ApiObjectBase* currentEncoder = mCurrentEncoder;
+        const ApiObjectBase* 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
@@ -178,9 +185,8 @@
         if (mError != nullptr) {
             return std::move(mError);
         }
-        if (currentEncoder != topLevelEncoder) {
-            return DAWN_VALIDATION_ERROR("Command buffer recording ended mid-pass");
-        }
+        DAWN_INVALID_IF(currentEncoder != topLevelEncoder,
+                        "Command buffer recording ended before %s was ended.", currentEncoder);
         return {};
     }