// // Copyright 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ContextVk.h: // Defines the class interface for ContextVk, implementing ContextImpl. // #ifndef LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_ #define LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_ #include "volk.h" #include "common/PackedEnums.h" #include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/vulkan/OverlayVk.h" #include "libANGLE/renderer/vulkan/PersistentCommandPool.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/vk_helpers.h" namespace angle { struct FeaturesVk; } // namespace angle namespace rx { class ProgramExecutableVk; class RendererVk; class WindowSurfaceVk; // The possible rotations of the surface/draw framebuffer, used for pre-rotating gl_Position // in the vertex shader. enum class SurfaceRotationType { Identity, Rotated90Degrees, Rotated180Degrees, Rotated270Degrees, FlippedIdentity, FlippedRotated90Degrees, FlippedRotated180Degrees, FlippedRotated270Degrees, InvalidEnum, EnumCount = InvalidEnum, }; struct CommandBatch final : angle::NonCopyable { CommandBatch(); ~CommandBatch(); CommandBatch(CommandBatch &&other); CommandBatch &operator=(CommandBatch &&other); void destroy(VkDevice device); vk::PrimaryCommandBuffer primaryCommands; // commandPool is for secondary CommandBuffer allocation vk::CommandPool commandPool; vk::Shared fence; Serial serial; }; class CommandQueue final : angle::NonCopyable { public: CommandQueue(); ~CommandQueue(); angle::Result init(vk::Context *context); void destroy(VkDevice device); void handleDeviceLost(RendererVk *renderer); bool hasInFlightCommands() const; angle::Result allocatePrimaryCommandBuffer(vk::Context *context, const vk::CommandPool &commandPool, vk::PrimaryCommandBuffer *commandBufferOut); angle::Result releasePrimaryCommandBuffer(vk::Context *context, vk::PrimaryCommandBuffer &&commandBuffer); void clearAllGarbage(RendererVk *renderer); angle::Result finishToSerial(vk::Context *context, Serial serial, uint64_t timeout); angle::Result submitFrame(vk::Context *context, egl::ContextPriority priority, const VkSubmitInfo &submitInfo, const vk::Shared &sharedFence, vk::GarbageList *currentGarbage, vk::CommandPool *commandPool, vk::PrimaryCommandBuffer &&commandBuffer); vk::Shared getLastSubmittedFence(const vk::Context *context) const; // Check to see which batches have finished completion (forward progress for // mLastCompletedQueueSerial, for example for when the application busy waits on a query // result). It would be nice if we didn't have to expose this for QueryVk::getResult. angle::Result checkCompletedCommands(vk::Context *context); private: angle::Result releaseToCommandBatch(vk::Context *context, vk::PrimaryCommandBuffer &&commandBuffer, vk::CommandPool *commandPool, CommandBatch *batch); vk::GarbageQueue mGarbageQueue; std::vector mInFlightCommands; // Keeps a free list of reusable primary command buffers. vk::PersistentCommandPool mPrimaryCommandPool; }; struct CommandBufferHelper : angle::NonCopyable { public: void bufferRead(vk::ResourceUseList *resourceUseList, VkAccessFlags readAccessType, vk::BufferHelper *buffer); void bufferWrite(vk::ResourceUseList *resourceUseList, VkAccessFlags writeAccessType, vk::BufferHelper *buffer); void imageRead(vk::ResourceUseList *resourceUseList, VkImageAspectFlags aspectFlags, vk::ImageLayout imageLayout, vk::ImageHelper *image); void imageWrite(vk::ResourceUseList *resourceUseList, VkImageAspectFlags aspectFlags, vk::ImageLayout imageLayout, vk::ImageHelper *image); void imageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, const VkImageMemoryBarrier &imageMemoryBarrier); vk::CommandBuffer &getCommandBuffer() { return mCommandBuffer; } protected: CommandBufferHelper(); ~CommandBufferHelper(); void executeBarriers(vk::PrimaryCommandBuffer *primary); VkPipelineStageFlags mImageBarrierSrcStageMask; VkPipelineStageFlags mImageBarrierDstStageMask; std::vector mImageMemoryBarriers; VkFlags mGlobalMemoryBarrierSrcAccess; VkFlags mGlobalMemoryBarrierDstAccess; VkPipelineStageFlags mGlobalMemoryBarrierStages; vk::CommandBuffer mCommandBuffer; }; class OutsideRenderPassCommandBuffer final : public CommandBufferHelper { public: OutsideRenderPassCommandBuffer(); ~OutsideRenderPassCommandBuffer(); void flushToPrimary(ContextVk *contextVk, vk::PrimaryCommandBuffer *primary); bool empty() const { return mCommandBuffer.empty(); } void reset(); }; class RenderPassCommandBuffer final : public CommandBufferHelper { public: RenderPassCommandBuffer(); ~RenderPassCommandBuffer(); void initialize(angle::PoolAllocator *poolAllocator); void beginRenderPass(const vk::Framebuffer &framebuffer, const gl::Rectangle &renderArea, const vk::RenderPassDesc &renderPassDesc, const vk::AttachmentOpsArray &renderPassAttachmentOps, const std::vector &clearValues, vk::CommandBuffer **commandBufferOut); void beginTransformFeedback(size_t validBufferCount, const VkBuffer *counterBuffers, bool rebindBuffer); void clearRenderPassColorAttachment(size_t attachmentIndex, const VkClearColorValue &clearValue) { SetBitField(mAttachmentOps[attachmentIndex].loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR); mClearValues[attachmentIndex].color = clearValue; } void clearRenderPassDepthAttachment(size_t attachmentIndex, float depth) { SetBitField(mAttachmentOps[attachmentIndex].loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR); SetBitField(mClearValues[attachmentIndex].depthStencil.depth, depth); } void clearRenderPassStencilAttachment(size_t attachmentIndex, uint32_t stencil) { SetBitField(mAttachmentOps[attachmentIndex].stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR); SetBitField(mClearValues[attachmentIndex].depthStencil.stencil, stencil); } void invalidateRenderPassColorAttachment(size_t attachmentIndex) { SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); } void invalidateRenderPassDepthAttachment(size_t attachmentIndex) { SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); } void invalidateRenderPassStencilAttachment(size_t attachmentIndex) { SetBitField(mAttachmentOps[attachmentIndex].stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); } void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, vk::ImageLayout finalLayout) { SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout); } const gl::Rectangle &getRenderArea() const { return mRenderArea; } angle::Result flushToPrimary(ContextVk *contextVk, vk::PrimaryCommandBuffer *primary); bool empty() const { return !started() && mCommandBuffer.empty(); } bool started() const { return mRenderPassStarted; } void reset(); void resumeTransformFeedbackIfStarted(); void pauseTransformFeedbackIfStarted(); uint32_t getAndResetCounter() { uint32_t count = mCounter; mCounter = 0; return count; } VkFramebuffer getFramebufferHandle() const { return mFramebuffer.getHandle(); } private: void addRenderPassCommandDiagnostics(ContextVk *contextVk); uint32_t mCounter; vk::RenderPassDesc mRenderPassDesc; vk::AttachmentOpsArray mAttachmentOps; vk::Framebuffer mFramebuffer; gl::Rectangle mRenderArea; gl::AttachmentArray mClearValues; bool mRenderPassStarted; // Transform feedback state gl::TransformFeedbackBuffersArray mTransformFeedbackCounterBuffers; uint32_t mValidTransformFeedbackBufferCount; bool mRebindTransformFeedbackBuffers; }; static constexpr uint32_t kMaxGpuEventNameLen = 32; using EventName = std::array; class ContextVk : public ContextImpl, public vk::Context { public: ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk *renderer); ~ContextVk() override; angle::Result initialize() override; void onDestroy(const gl::Context *context) override; // Flush and finish. angle::Result flush(const gl::Context *context) override; angle::Result finish(const gl::Context *context) override; // Drawing methods. angle::Result drawArrays(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count) override; angle::Result drawArraysInstanced(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count, GLsizei instanceCount) override; angle::Result drawArraysInstancedBaseInstance(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count, GLsizei instanceCount, GLuint baseInstance) override; angle::Result drawElements(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices) override; angle::Result drawElementsBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLint baseVertex) override; angle::Result drawElementsInstanced(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instanceCount) override; angle::Result drawElementsInstancedBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instanceCount, GLint baseVertex) override; angle::Result drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instances, GLint baseVertex, GLuint baseInstance) override; angle::Result drawRangeElements(const gl::Context *context, gl::PrimitiveMode mode, GLuint start, GLuint end, GLsizei count, gl::DrawElementsType type, const void *indices) override; angle::Result drawRangeElementsBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLuint start, GLuint end, GLsizei count, gl::DrawElementsType type, const void *indices, GLint baseVertex) override; angle::Result drawArraysIndirect(const gl::Context *context, gl::PrimitiveMode mode, const void *indirect) override; angle::Result drawElementsIndirect(const gl::Context *context, gl::PrimitiveMode mode, gl::DrawElementsType type, const void *indirect) override; angle::Result clearWithRenderPassOp(const gl::Rectangle &clearArea, gl::DrawBufferMask clearColorBuffers, bool clearDepth, bool clearStencil, const VkClearColorValue &clearColorValue, const VkClearDepthStencilValue &clearDepthStencilValue); // Device loss gl::GraphicsResetStatus getResetStatus() override; // Vendor and description strings. std::string getVendorString() const override; std::string getRendererDescription() const override; // EXT_debug_marker angle::Result insertEventMarker(GLsizei length, const char *marker) override; angle::Result pushGroupMarker(GLsizei length, const char *marker) override; angle::Result popGroupMarker() override; // KHR_debug angle::Result pushDebugGroup(const gl::Context *context, GLenum source, GLuint id, const std::string &message) override; angle::Result popDebugGroup(const gl::Context *context) override; bool isViewportFlipEnabledForDrawFBO() const; bool isViewportFlipEnabledForReadFBO() const; // When the device/surface is rotated such that the surface's aspect ratio is different than // the native device (e.g. 90 degrees), the width and height of the viewport, scissor, and // render area must be swapped. bool isRotatedAspectRatioForDrawFBO() const; bool isRotatedAspectRatioForReadFBO() const; void invalidateProgramBindingHelper(const gl::State &glState); angle::Result invalidateProgramExecutableHelper(const gl::Context *context); // State sync with dirty bits. angle::Result syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits, const gl::State::DirtyBits &bitMask) override; // Disjoint timer queries GLint getGPUDisjoint() override; GLint64 getTimestamp() override; // Context switching angle::Result onMakeCurrent(const gl::Context *context) override; angle::Result onUnMakeCurrent(const gl::Context *context) override; // Native capabilities, unmodified by gl::Context. gl::Caps getNativeCaps() const override; const gl::TextureCapsMap &getNativeTextureCaps() const override; const gl::Extensions &getNativeExtensions() const override; const gl::Limitations &getNativeLimitations() const override; // Shader creation CompilerImpl *createCompiler() override; ShaderImpl *createShader(const gl::ShaderState &state) override; ProgramImpl *createProgram(const gl::ProgramState &state) override; // Framebuffer creation FramebufferImpl *createFramebuffer(const gl::FramebufferState &state) override; // Texture creation TextureImpl *createTexture(const gl::TextureState &state) override; // Renderbuffer creation RenderbufferImpl *createRenderbuffer(const gl::RenderbufferState &state) override; // Buffer creation BufferImpl *createBuffer(const gl::BufferState &state) override; // Vertex Array creation VertexArrayImpl *createVertexArray(const gl::VertexArrayState &state) override; // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; SyncImpl *createSync() override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback( const gl::TransformFeedbackState &state) override; // Sampler object creation SamplerImpl *createSampler(const gl::SamplerState &state) override; // Program Pipeline object creation ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; // Memory object creation. MemoryObjectImpl *createMemoryObject() override; // Semaphore creation. SemaphoreImpl *createSemaphore() override; // Overlay creation. OverlayImpl *createOverlay(const gl::OverlayState &state) override; angle::Result dispatchCompute(const gl::Context *context, GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) override; angle::Result dispatchComputeIndirect(const gl::Context *context, GLintptr indirect) override; angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override; angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override; VkDevice getDevice() const; egl::ContextPriority getPriority() const { return mContextPriority; } ANGLE_INLINE const angle::FeaturesVk &getFeatures() const { return mRenderer->getFeatures(); } ANGLE_INLINE void invalidateVertexAndIndexBuffers() { // TODO: Make the pipeline invalidate more fine-grained. Only need to dirty here if PSO // VtxInput state (stride, fmt, inputRate...) has changed. http://anglebug.com/3256 invalidateCurrentGraphicsPipeline(); mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER); } ANGLE_INLINE void invalidateVertexBuffers() { mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); } ANGLE_INLINE void onVertexAttributeChange(size_t attribIndex, GLuint stride, GLuint divisor, angle::FormatID format, GLuint relativeOffset) { invalidateVertexAndIndexBuffers(); // Set divisor to 1 for attribs with emulated divisor mGraphicsPipelineDesc->updateVertexInput( &mGraphicsPipelineTransition, static_cast(attribIndex), stride, divisor > mRenderer->getMaxVertexAttribDivisor() ? 1 : divisor, format, relativeOffset); } void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask); void onDrawFramebufferChange(FramebufferVk *framebufferVk); void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; } void invalidateCurrentTransformFeedbackBuffers(); void invalidateCurrentTransformFeedbackState(); void onTransformFeedbackStateChanged(); // When UtilsVk issues draw or dispatch calls, it binds descriptor sets that the context is not // aware of. This function is called to make sure affected descriptor set bindings are dirtied // for the next application draw/dispatch call. void invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet); void invalidateComputeDescriptorSet(uint32_t usedDescriptorSet); void optimizeRenderPassForPresent(VkFramebuffer framebufferHandle); vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType); const VkClearValue &getClearColorValue() const; const VkClearValue &getClearDepthStencilValue() const; VkColorComponentFlags getClearColorMask() const; angle::Result getIncompleteTexture(const gl::Context *context, gl::TextureType type, gl::Texture **textureOut); void updateColorMask(const gl::BlendState &blendState); void updateSampleMask(const gl::State &glState); void handleError(VkResult errorCode, const char *file, const char *function, unsigned int line) override; const gl::ActiveTextureArray &getActiveTextures() const { return mActiveTextures; } const gl::ActiveTextureArray &getActiveImages() const { return mActiveImages; } void setIndexBufferDirty() { mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER); mLastIndexBufferOffset = reinterpret_cast(angle::DirtyPointer); } void insertWaitSemaphore(const vk::Semaphore *waitSemaphore); bool shouldFlush(); angle::Result flushImpl(const vk::Semaphore *semaphore); angle::Result finishImpl(); void addWaitSemaphore(VkSemaphore semaphore); const vk::CommandPool &getCommandPool() const; Serial getCurrentQueueSerial() const { return mRenderer->getCurrentQueueSerial(); } Serial getLastSubmittedQueueSerial() const { return mRenderer->getLastSubmittedQueueSerial(); } Serial getLastCompletedQueueSerial() const { return mRenderer->getLastCompletedQueueSerial(); } bool isSerialInUse(Serial serial) const; template void addGarbage(T *object) { if (object->valid()) { mCurrentGarbage.emplace_back(vk::GetGarbage(object)); } } // It would be nice if we didn't have to expose this for QueryVk::getResult. angle::Result checkCompletedCommands(); // Wait for completion of batches until (at least) batch with given serial is finished. angle::Result finishToSerial(Serial serial); angle::Result getCompatibleRenderPass(const vk::RenderPassDesc &desc, vk::RenderPass **renderPassOut); angle::Result getRenderPassWithOps(const vk::RenderPassDesc &desc, const vk::AttachmentOpsArray &ops, vk::RenderPass **renderPassOut); // Get (or allocate) the fence that will be signaled on next submission. angle::Result getNextSubmitFence(vk::Shared *sharedFenceOut); vk::Shared getLastSubmittedFence() const; vk::ShaderLibrary &getShaderLibrary() { return mShaderLibrary; } UtilsVk &getUtils() { return mUtils; } angle::Result getTimestamp(uint64_t *timestampOut); // Create Begin/End/Instant GPU trace events, which take their timestamps from GPU queries. // The events are queued until the query results are available. Possible values for `phase` // are TRACE_EVENT_PHASE_* ANGLE_INLINE angle::Result traceGpuEvent(vk::PrimaryCommandBuffer *commandBuffer, char phase, const EventName &name) { if (mGpuEventsEnabled) return traceGpuEventImpl(commandBuffer, phase, name); return angle::Result::Continue; } RenderPassCache &getRenderPassCache() { return mRenderPassCache; } vk::DescriptorSetLayoutDesc getDriverUniformsDescriptorSetDesc( VkShaderStageFlags shaderStages) const; // We use texture serials to optimize texture binding updates. Each permutation of a // {VkImage/VkSampler} generates a unique serial. These serials are combined to form a unique // signature for each descriptor set. This allows us to keep a cache of descriptor sets and // avoid calling vkAllocateDesctiporSets each texture update. Serial generateTextureSerial() { return mTextureSerialFactory.generate(); } const vk::TextureDescriptorDesc &getActiveTexturesDesc() const { return mActiveTexturesDesc; } Serial generateAttachmentImageSerial() { return mAttachmentImageSerialFactory.generate(); } angle::Result updateScissor(const gl::State &glState); bool emulateSeamfulCubeMapSampling() const { return mEmulateSeamfulCubeMapSampling; } bool useOldRewriteStructSamplers() const { return mUseOldRewriteStructSamplers; } const gl::OverlayType *getOverlay() const { return mState.getOverlay(); } vk::ResourceUseList &getResourceUseList() { return mResourceUseList; } angle::Result onBufferRead(VkAccessFlags readAccessType, vk::BufferHelper *buffer); angle::Result onBufferWrite(VkAccessFlags writeAccessType, vk::BufferHelper *buffer); angle::Result onImageRead(VkImageAspectFlags aspectFlags, vk::ImageLayout imageLayout, vk::ImageHelper *image); angle::Result onImageWrite(VkImageAspectFlags aspectFlags, vk::ImageLayout imageLayout, vk::ImageHelper *image); void onRenderPassImageWrite(VkImageAspectFlags aspectFlags, vk::ImageLayout imageLayout, vk::ImageHelper *image); angle::Result endRenderPassAndGetCommandBuffer(vk::CommandBuffer **commandBufferOut) { ANGLE_TRY(endRenderPass()); *commandBufferOut = &mOutsideRenderPassCommands.getCommandBuffer(); return angle::Result::Continue; } angle::Result flushAndBeginRenderPass(const vk::Framebuffer &framebuffer, const gl::Rectangle &renderArea, const vk::RenderPassDesc &renderPassDesc, const vk::AttachmentOpsArray &renderPassAttachmentOps, const std::vector &clearValues, vk::CommandBuffer **commandBufferOut); bool hasStartedRenderPass() const { return !mRenderPassCommands.empty(); } RenderPassCommandBuffer &getStartedRenderPassCommands() { ASSERT(hasStartedRenderPass()); return mRenderPassCommands; } angle::Result flushAndGetPrimaryCommandBuffer(vk::PrimaryCommandBuffer **primaryCommands) { flushOutsideRenderPassCommands(); ANGLE_TRY(endRenderPass()); *primaryCommands = &mPrimaryCommands; // We assume any calling code is going to record primary commands. mHasPrimaryCommands = true; return angle::Result::Continue; } egl::ContextPriority getContextPriority() const override { return mContextPriority; } angle::Result startRenderPass(gl::Rectangle renderArea); angle::Result endRenderPass(); angle::Result syncExternalMemory(); void addCommandBufferDiagnostics(const std::string &commandBufferDiagnostics); VkIndexType getVkIndexType(gl::DrawElementsType glIndexType) const; size_t getVkIndexTypeSize(gl::DrawElementsType glIndexType) const; bool shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const; ANGLE_INLINE bool isBresenhamEmulationEnabled(const gl::PrimitiveMode mode) { return getFeatures().basicGLLineRasterization.enabled && gl::IsLineMode(mode); } const ProgramExecutableVk *getExecutable() const { return mExecutable; } ProgramExecutableVk *getExecutable() { return mExecutable; } bool isRobustResourceInitEnabled() const override; // occlusion query void beginOcclusionQuery(QueryVk *queryVk); void endOcclusionQuery(QueryVk *queryVk); private: // Dirty bits. enum DirtyBitType : size_t { DIRTY_BIT_DEFAULT_ATTRIBS, DIRTY_BIT_PIPELINE, DIRTY_BIT_TEXTURES, DIRTY_BIT_VERTEX_BUFFERS, DIRTY_BIT_INDEX_BUFFER, DIRTY_BIT_DRIVER_UNIFORMS, DIRTY_BIT_DRIVER_UNIFORMS_BINDING, DIRTY_BIT_SHADER_RESOURCES, // excluding textures, which are handled separately. DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS, DIRTY_BIT_TRANSFORM_FEEDBACK_STATE, DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME, DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_MAX, }; using DirtyBits = angle::BitSet; using DirtyBitHandler = angle::Result (ContextVk::*)(const gl::Context *, vk::CommandBuffer *commandBuffer); struct DriverUniformsDescriptorSet { vk::DynamicBuffer dynamicBuffer; VkDescriptorSet descriptorSet; uint32_t dynamicOffset; vk::BindingPointer descriptorSetLayout; vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; DriverUniformsDescriptorSet(); ~DriverUniformsDescriptorSet(); void init(RendererVk *rendererVk); void destroy(RendererVk *rendererVk); }; enum class PipelineType { Graphics = 0, Compute = 1, InvalidEnum = 2, EnumCount = 2, }; // The GpuEventQuery struct holds together a timestamp query and enough data to create a // trace event based on that. Use traceGpuEvent to insert such queries. They will be readback // when the results are available, without inserting a GPU bubble. // // - eventName will be the reported name of the event // - phase is either 'B' (duration begin), 'E' (duration end) or 'i' (instant // event). // See Google's "Trace Event Format": // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU // - serial is the serial of the batch the query was submitted on. Until the batch is // submitted, the query is not checked to avoid incuring a flush. struct GpuEventQuery final { EventName name; char phase; vk::QueryHelper queryHelper; }; // Once a query result is available, the timestamp is read and a GpuEvent object is kept until // the next clock sync, at which point the clock drift is compensated in the results before // handing them off to the application. struct GpuEvent final { uint64_t gpuTimestampCycles; std::array name; char phase; }; struct GpuClockSyncInfo { double gpuTimestampS; double cpuTimestampS; }; angle::Result setupDraw(const gl::Context *context, gl::PrimitiveMode mode, GLint firstVertexOrInvalid, GLsizei vertexOrIndexCount, GLsizei instanceCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices, DirtyBits dirtyBitMask, vk::CommandBuffer **commandBufferOut); angle::Result setupIndexedDraw(const gl::Context *context, gl::PrimitiveMode mode, GLsizei indexCount, GLsizei instanceCount, gl::DrawElementsType indexType, const void *indices, vk::CommandBuffer **commandBufferOut); angle::Result setupIndirectDraw(const gl::Context *context, gl::PrimitiveMode mode, DirtyBits dirtyBitMask, vk::BufferHelper *indirectBuffer, VkDeviceSize indirectBufferOffset, vk::CommandBuffer **commandBufferOut); angle::Result setupIndexedIndirectDraw(const gl::Context *context, gl::PrimitiveMode mode, gl::DrawElementsType indexType, vk::BufferHelper *indirectBuffer, VkDeviceSize indirectBufferOffset, vk::CommandBuffer **commandBufferOut); angle::Result setupLineLoopIndexedIndirectDraw(const gl::Context *context, gl::PrimitiveMode mode, gl::DrawElementsType indexType, vk::BufferHelper *srcIndirectBuf, VkDeviceSize indirectBufferOffset, vk::CommandBuffer **commandBufferOut, vk::BufferHelper **indirectBufferOut, VkDeviceSize *indirectBufferOffsetOut); angle::Result setupLineLoopIndirectDraw(const gl::Context *context, gl::PrimitiveMode mode, vk::BufferHelper *indirectBuffer, VkDeviceSize indirectBufferOffset, vk::CommandBuffer **commandBufferOut, vk::BufferHelper **indirectBufferOut, VkDeviceSize *indirectBufferOffsetOut); angle::Result setupLineLoopDraw(const gl::Context *context, gl::PrimitiveMode mode, GLint firstVertex, GLsizei vertexOrIndexCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices, vk::CommandBuffer **commandBufferOut, uint32_t *numIndicesOut); angle::Result setupDispatch(const gl::Context *context, vk::CommandBuffer **commandBufferOut); void updateViewport(FramebufferVk *framebufferVk, const gl::Rectangle &viewport, float nearPlane, float farPlane, bool invertViewport); void updateDepthRange(float nearPlane, float farPlane); void updateFlipViewportDrawFramebuffer(const gl::State &glState); void updateFlipViewportReadFramebuffer(const gl::State &glState); void updateSurfaceRotationDrawFramebuffer(const gl::State &glState); void updateSurfaceRotationReadFramebuffer(const gl::State &glState); angle::Result updateActiveTextures(const gl::Context *context); angle::Result updateActiveImages(const gl::Context *context, CommandBufferHelper *commandBufferHelper); angle::Result updateDefaultAttribute(size_t attribIndex); ANGLE_INLINE void invalidateCurrentGraphicsPipeline() { mGraphicsDirtyBits |= mNewGraphicsPipelineDirtyBits; // The draw mode may have changed, toggling whether line rasterization is // enabled or not, which means we need to recreate the graphics pipeline. mCurrentGraphicsPipeline = nullptr; } ANGLE_INLINE void invalidateCurrentComputePipeline() { mComputeDirtyBits.set(DIRTY_BIT_PIPELINE); mCurrentComputePipeline = nullptr; } void invalidateCurrentDefaultUniforms(); angle::Result invalidateCurrentTextures(const gl::Context *context); void invalidateCurrentShaderResources(); void invalidateGraphicsDriverUniforms(); void invalidateDriverUniforms(); // Handlers for graphics pipeline dirty bits. angle::Result handleDirtyGraphicsDefaultAttribs(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsPipeline(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsTextures(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsVertexBuffers(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsIndexBuffer(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsDriverUniforms(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsDriverUniformsBinding(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsShaderResources(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsTransformFeedbackBuffersEmulation( const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsTransformFeedbackBuffersExtension( const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsTransformFeedbackState(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyGraphicsTransformFeedbackResume(const gl::Context *context, vk::CommandBuffer *commandBuffer); // Handlers for compute pipeline dirty bits. angle::Result handleDirtyComputePipeline(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyComputeTextures(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyComputeDriverUniforms(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyComputeDriverUniformsBinding(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result handleDirtyComputeShaderResources(const gl::Context *context, vk::CommandBuffer *commandBuffer); // Common parts of the common dirty bit handlers. angle::Result handleDirtyTexturesImpl(CommandBufferHelper *commandBufferHelper); angle::Result handleDirtyShaderResourcesImpl(const gl::Context *context, CommandBufferHelper *commandBufferHelper); void handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer *commandBuffer, VkPipelineBindPoint bindPoint, const DriverUniformsDescriptorSet &driverUniforms); angle::Result handleDirtyDescriptorSets(const gl::Context *context, vk::CommandBuffer *commandBuffer); angle::Result allocateDriverUniforms(size_t driverUniformsSize, DriverUniformsDescriptorSet *driverUniforms, VkBuffer *bufferOut, uint8_t **ptrOut, bool *newBufferOut); angle::Result updateDriverUniformsDescriptorSet(VkBuffer buffer, bool newBuffer, size_t driverUniformsSize, DriverUniformsDescriptorSet *driverUniforms); void writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut, size_t offsetsSize); angle::Result submitFrame(const VkSubmitInfo &submitInfo, vk::PrimaryCommandBuffer &&commandBuffer); angle::Result memoryBarrierImpl(GLbitfield barriers, VkPipelineStageFlags stageMask); angle::Result synchronizeCpuGpuTime(); angle::Result traceGpuEventImpl(vk::PrimaryCommandBuffer *commandBuffer, char phase, const EventName &name); angle::Result checkCompletedGpuEvents(); void flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS); void handleDeviceLost(); void waitForSwapchainImageIfNecessary(); bool shouldEmulateSeamfulCubeMapSampling() const; bool shouldUseOldRewriteStructSamplers() const; void clearAllGarbage(); angle::Result ensureSubmitFenceInitialized(); angle::Result startPrimaryCommandBuffer(); bool hasRecordedCommands(); void dumpCommandStreamDiagnostics(); void flushOutsideRenderPassCommands(); ANGLE_INLINE void onRenderPassFinished() { mRenderPassCommandBuffer = nullptr; } void initIndexTypeMap(); std::array mGraphicsDirtyBitHandlers; std::array mComputeDirtyBitHandlers; vk::CommandBuffer *mRenderPassCommandBuffer; vk::PipelineHelper *mCurrentGraphicsPipeline; vk::PipelineAndSerial *mCurrentComputePipeline; gl::PrimitiveMode mCurrentDrawMode; WindowSurfaceVk *mCurrentWindowSurface; // Records the current rotation of the surface (draw/read) framebuffer, derived from // mCurrentWindowSurface->getPreTransform(). SurfaceRotationType mCurrentRotationDrawFramebuffer; SurfaceRotationType mCurrentRotationReadFramebuffer; // Keep a cached pipeline description structure that can be used to query the pipeline cache. // Kept in a pointer so allocations can be aligned, and structs can be portably packed. std::unique_ptr mGraphicsPipelineDesc; vk::GraphicsPipelineTransitionBits mGraphicsPipelineTransition; // These pools are externally sychronized, so cannot be accessed from different // threads simultaneously. Hence, we keep them in the ContextVk instead of the RendererVk. // Note that this implementation would need to change in shared resource scenarios. Likely // we'd instead share a single set of pools between the share groups. vk::DynamicDescriptorPool mDriverUniformsDescriptorPool; angle::PackedEnumMap mQueryPools; // Dirty bits. DirtyBits mGraphicsDirtyBits; DirtyBits mComputeDirtyBits; DirtyBits mNonIndexedDirtyBitsMask; DirtyBits mIndexedDirtyBitsMask; DirtyBits mNewGraphicsCommandBufferDirtyBits; DirtyBits mNewComputeCommandBufferDirtyBits; DirtyBits mNewGraphicsPipelineDirtyBits; // Cached back-end objects. VertexArrayVk *mVertexArray; FramebufferVk *mDrawFramebuffer; ProgramVk *mProgram; ProgramPipelineVk *mProgramPipeline; ProgramExecutableVk *mExecutable; // occlusion query QueryVk *mActiveQueryAnySamples; QueryVk *mActiveQueryAnySamplesConservative; // Graph resource used to record dispatch commands and hold resource dependencies. vk::DispatchHelper mDispatcher; // The offset we had the last time we bound the index buffer. const GLvoid *mLastIndexBufferOffset; gl::DrawElementsType mCurrentDrawElementsType; angle::PackedEnumMap mIndexTypeMap; // Cache the current draw call's firstVertex to be passed to // TransformFeedbackVk::getBufferOffsets. Unfortunately, gl_BaseVertex support in Vulkan is // not yet ubiquitous, which would have otherwise removed the need for this value to be passed // as a uniform. GLint mXfbBaseVertex; // Cache the current draw call's vertex count as well to support instanced draw calls GLuint mXfbVertexCountPerInstance; // Cached clear value/mask for color and depth/stencil. VkClearValue mClearColorValue; VkClearValue mClearDepthStencilValue; VkColorComponentFlags mClearColorMask; IncompleteTextureSet mIncompleteTextures; // If the current surface bound to this context wants to have all rendering flipped vertically. // Updated on calls to onMakeCurrent. bool mFlipYForCurrentSurface; bool mFlipViewportForDrawFramebuffer; bool mFlipViewportForReadFramebuffer; // If any host-visible buffer is written by the GPU since last submission, a barrier is inserted // at the end of the command buffer to make that write available to the host. bool mIsAnyHostVisibleBufferWritten; // Whether this context should do seamful cube map sampling emulation. bool mEmulateSeamfulCubeMapSampling; // Whether this context should use the old version of the // RewriteStructSamplers pass. bool mUseOldRewriteStructSamplers; angle::PackedEnumMap mDriverUniforms; // This cache should also probably include the texture index (shader location) and array // index (also in the shader). This info is used in the descriptor update step. gl::ActiveTextureArray mActiveTextures; vk::TextureDescriptorDesc mActiveTexturesDesc; gl::ActiveTextureArray mActiveImages; // "Current Value" aka default vertex attribute state. gl::AttributesMask mDirtyDefaultAttribsMask; gl::AttribArray mDefaultAttribBuffers; // We use a single pool for recording commands. We also keep a free list for pool recycling. vk::CommandPool mCommandPool; CommandQueue mCommandQueue; vk::GarbageList mCurrentGarbage; RenderPassCache mRenderPassCache; // mSubmitFence is the fence that's going to be signaled at the next submission. This is used // to support SyncVk objects, which may outlive the context (as EGLSync objects). // // TODO(geofflang): this is in preparation for moving RendererVk functionality to ContextVk, and // is otherwise unnecessary as the SyncVk objects don't actually outlive the renderer currently. // http://anglebug.com/2701 vk::Shared mSubmitFence; // Pool allocator used for command graph but may be expanded to other allocations angle::PoolAllocator mPoolAllocator; // When the command graph is disabled we record commands completely linearly. We have plans to // reorder independent draws so that we can create fewer RenderPasses in some scenarios. OutsideRenderPassCommandBuffer mOutsideRenderPassCommands; RenderPassCommandBuffer mRenderPassCommands; vk::PrimaryCommandBuffer mPrimaryCommands; bool mHasPrimaryCommands; // Internal shader library. vk::ShaderLibrary mShaderLibrary; UtilsVk mUtils; bool mGpuEventsEnabled; vk::DynamicQueryPool mGpuEventQueryPool; // A list of queries that have yet to be turned into an event (their result is not yet // available). std::vector mInFlightGpuEventQueries; // A list of gpu events since the last clock sync. std::vector mGpuEvents; // Semaphores that must be waited on in the next submission. std::vector mWaitSemaphores; std::vector mWaitSemaphoreStageMasks; // Hold information from the last gpu clock sync for future gpu-to-cpu timestamp conversions. GpuClockSyncInfo mGpuClockSync; // The very first timestamp queried for a GPU event is used as origin, so event timestamps would // have a value close to zero, to avoid losing 12 bits when converting these 64 bit values to // double. uint64_t mGpuEventTimestampOrigin; // Used to count events for tracing. uint32_t mPrimaryBufferCounter; uint32_t mRenderPassCounter; // Generators for texture & framebuffer serials. SerialFactory mTextureSerialFactory; SerialFactory mAttachmentImageSerialFactory; gl::State::DirtyBits mPipelineDirtyBitsMask; // List of all resources currently being used by this ContextVk's recorded commands. vk::ResourceUseList mResourceUseList; egl::ContextPriority mContextPriority; std::vector mCommandBufferDiagnostics; }; } // namespace rx #endif // LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_