mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #2870 from FernandoS27/multi-draw
Implement a MME Draw commands Inliner and correct host instance drawing
This commit is contained in:
		
						commit
						9d69206cd0
					
				@ -92,6 +92,10 @@ void Maxwell3D::InitializeRegisterDefaults() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Some games (like Super Mario Odyssey) assume that SRGB is enabled.
 | 
					    // Some games (like Super Mario Odyssey) assume that SRGB is enabled.
 | 
				
			||||||
    regs.framebuffer_srgb = 1;
 | 
					    regs.framebuffer_srgb = 1;
 | 
				
			||||||
 | 
					    mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true;
 | 
				
			||||||
 | 
					    mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true;
 | 
				
			||||||
 | 
					    mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
 | 
				
			||||||
 | 
					    mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
 | 
					#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
 | 
				
			||||||
@ -256,6 +260,9 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Execute the current macro.
 | 
					    // Execute the current macro.
 | 
				
			||||||
    macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
 | 
					    macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
 | 
				
			||||||
 | 
					    if (mme_draw.current_mode != MMEDrawMode::Undefined) {
 | 
				
			||||||
 | 
					        FlushMMEInlineDraw();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
 | 
					void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
 | 
				
			||||||
@ -416,6 +423,97 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
 | 
				
			||||||
 | 
					    if (mme_draw.current_mode == MMEDrawMode::Undefined) {
 | 
				
			||||||
 | 
					        if (mme_draw.gl_begin_consume) {
 | 
				
			||||||
 | 
					            mme_draw.current_mode = expected_mode;
 | 
				
			||||||
 | 
					            mme_draw.current_count = count;
 | 
				
			||||||
 | 
					            mme_draw.instance_count = 1;
 | 
				
			||||||
 | 
					            mme_draw.gl_begin_consume = false;
 | 
				
			||||||
 | 
					            mme_draw.gl_end_count = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count &&
 | 
				
			||||||
 | 
					            mme_draw.instance_mode && mme_draw.gl_begin_consume) {
 | 
				
			||||||
 | 
					            mme_draw.instance_count++;
 | 
				
			||||||
 | 
					            mme_draw.gl_begin_consume = false;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            FlushMMEInlineDraw();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Tail call in case it needs to retry.
 | 
				
			||||||
 | 
					    StepInstance(expected_mode, count);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Maxwell3D::CallMethodFromMME(const GPU::MethodCall& method_call) {
 | 
				
			||||||
 | 
					    const u32 method = method_call.method;
 | 
				
			||||||
 | 
					    if (mme_inline[method]) {
 | 
				
			||||||
 | 
					        regs.reg_array[method] = method_call.argument;
 | 
				
			||||||
 | 
					        if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) ||
 | 
				
			||||||
 | 
					            method == MAXWELL3D_REG_INDEX(index_array.count)) {
 | 
				
			||||||
 | 
					            const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count)
 | 
				
			||||||
 | 
					                                                  ? MMEDrawMode::Array
 | 
				
			||||||
 | 
					                                                  : MMEDrawMode::Indexed;
 | 
				
			||||||
 | 
					            StepInstance(expected_mode, method_call.argument);
 | 
				
			||||||
 | 
					        } else if (method == MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)) {
 | 
				
			||||||
 | 
					            mme_draw.instance_mode =
 | 
				
			||||||
 | 
					                (regs.draw.instance_next != 0) || (regs.draw.instance_cont != 0);
 | 
				
			||||||
 | 
					            mme_draw.gl_begin_consume = true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            mme_draw.gl_end_count++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (mme_draw.current_mode != MMEDrawMode::Undefined) {
 | 
				
			||||||
 | 
					            FlushMMEInlineDraw();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        CallMethod(method_call);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Maxwell3D::FlushMMEInlineDraw() {
 | 
				
			||||||
 | 
					    LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
 | 
				
			||||||
 | 
					              regs.vertex_buffer.count);
 | 
				
			||||||
 | 
					    ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
 | 
				
			||||||
 | 
					    ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto debug_context = system.GetGPUDebugContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (debug_context) {
 | 
				
			||||||
 | 
					        debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Both instance configuration registers can not be set at the same time.
 | 
				
			||||||
 | 
					    ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
 | 
				
			||||||
 | 
					               "Illegal combination of instancing parameters");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
 | 
				
			||||||
 | 
					    if (ShouldExecute()) {
 | 
				
			||||||
 | 
					        rasterizer.DrawMultiBatch(is_indexed);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (debug_context) {
 | 
				
			||||||
 | 
					        debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
 | 
				
			||||||
 | 
					    // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
 | 
				
			||||||
 | 
					    // it's possible that it is incorrect and that there is some other register used to specify the
 | 
				
			||||||
 | 
					    // drawing mode.
 | 
				
			||||||
 | 
					    if (is_indexed) {
 | 
				
			||||||
 | 
					        regs.index_array.count = 0;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        regs.vertex_buffer.count = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mme_draw.current_mode = MMEDrawMode::Undefined;
 | 
				
			||||||
 | 
					    mme_draw.current_count = 0;
 | 
				
			||||||
 | 
					    mme_draw.instance_count = 0;
 | 
				
			||||||
 | 
					    mme_draw.instance_mode = false;
 | 
				
			||||||
 | 
					    mme_draw.gl_begin_consume = false;
 | 
				
			||||||
 | 
					    mme_draw.gl_end_count = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Maxwell3D::ProcessMacroUpload(u32 data) {
 | 
					void Maxwell3D::ProcessMacroUpload(u32 data) {
 | 
				
			||||||
    ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
 | 
					    ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
 | 
				
			||||||
               "upload_address exceeded macro_memory size!");
 | 
					               "upload_address exceeded macro_memory size!");
 | 
				
			||||||
@ -564,7 +662,9 @@ void Maxwell3D::DrawArrays() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
 | 
					    const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
 | 
				
			||||||
    rasterizer.AccelerateDrawBatch(is_indexed);
 | 
					    if (ShouldExecute()) {
 | 
				
			||||||
 | 
					        rasterizer.DrawBatch(is_indexed);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (debug_context) {
 | 
					    if (debug_context) {
 | 
				
			||||||
        debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
 | 
					        debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
 | 
				
			||||||
 | 
				
			|||||||
@ -811,8 +811,9 @@ public:
 | 
				
			|||||||
                INSERT_PADDING_WORDS(0x21);
 | 
					                INSERT_PADDING_WORDS(0x21);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                u32 vb_element_base;
 | 
					                u32 vb_element_base;
 | 
				
			||||||
 | 
					                u32 vb_base_instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                INSERT_PADDING_WORDS(0x36);
 | 
					                INSERT_PADDING_WORDS(0x35);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                union {
 | 
					                union {
 | 
				
			||||||
                    BitField<0, 1, u32> c0;
 | 
					                    BitField<0, 1, u32> c0;
 | 
				
			||||||
@ -1238,6 +1239,11 @@ public:
 | 
				
			|||||||
    /// Write the value to the register identified by method.
 | 
					    /// Write the value to the register identified by method.
 | 
				
			||||||
    void CallMethod(const GPU::MethodCall& method_call);
 | 
					    void CallMethod(const GPU::MethodCall& method_call);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Write the value to the register identified by method.
 | 
				
			||||||
 | 
					    void CallMethodFromMME(const GPU::MethodCall& method_call);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void FlushMMEInlineDraw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Given a Texture Handle, returns the TSC and TIC entries.
 | 
					    /// Given a Texture Handle, returns the TSC and TIC entries.
 | 
				
			||||||
    Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
 | 
					    Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
 | 
				
			||||||
                                            std::size_t offset) const;
 | 
					                                            std::size_t offset) const;
 | 
				
			||||||
@ -1263,6 +1269,21 @@ public:
 | 
				
			|||||||
        return execute_on;
 | 
					        return execute_on;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum class MMEDrawMode : u32 {
 | 
				
			||||||
 | 
					        Undefined,
 | 
				
			||||||
 | 
					        Array,
 | 
				
			||||||
 | 
					        Indexed,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct MMEDrawState {
 | 
				
			||||||
 | 
					        MMEDrawMode current_mode{MMEDrawMode::Undefined};
 | 
				
			||||||
 | 
					        u32 current_count{};
 | 
				
			||||||
 | 
					        u32 instance_count{};
 | 
				
			||||||
 | 
					        bool instance_mode{};
 | 
				
			||||||
 | 
					        bool gl_begin_consume{};
 | 
				
			||||||
 | 
					        u32 gl_end_count{};
 | 
				
			||||||
 | 
					    } mme_draw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    void InitializeRegisterDefaults();
 | 
					    void InitializeRegisterDefaults();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1275,6 +1296,8 @@ private:
 | 
				
			|||||||
    /// Start offsets of each macro in macro_memory
 | 
					    /// Start offsets of each macro in macro_memory
 | 
				
			||||||
    std::array<u32, 0x80> macro_positions = {};
 | 
					    std::array<u32, 0x80> macro_positions = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::array<bool, Regs::NUM_REGS> mme_inline{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Memory for macro code
 | 
					    /// Memory for macro code
 | 
				
			||||||
    MacroMemory macro_memory;
 | 
					    MacroMemory macro_memory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1346,6 +1369,9 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Handles a write to the VERTEX_END_GL register, triggering a draw.
 | 
					    /// Handles a write to the VERTEX_END_GL register, triggering a draw.
 | 
				
			||||||
    void DrawArrays();
 | 
					    void DrawArrays();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handles a instance drawcall from MME
 | 
				
			||||||
 | 
					    void StepInstance(MMEDrawMode expected_mode, u32 count);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ASSERT_REG_POSITION(field_name, position)                                                  \
 | 
					#define ASSERT_REG_POSITION(field_name, position)                                                  \
 | 
				
			||||||
@ -1402,6 +1428,7 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
 | 
				
			|||||||
ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
 | 
					ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
 | 
				
			||||||
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
 | 
					ASSERT_REG_POSITION(screen_y_control, 0x4EB);
 | 
				
			||||||
ASSERT_REG_POSITION(vb_element_base, 0x50D);
 | 
					ASSERT_REG_POSITION(vb_element_base, 0x50D);
 | 
				
			||||||
 | 
					ASSERT_REG_POSITION(vb_base_instance, 0x50E);
 | 
				
			||||||
ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
 | 
					ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
 | 
				
			||||||
ASSERT_REG_POSITION(point_size, 0x546);
 | 
					ASSERT_REG_POSITION(point_size, 0x546);
 | 
				
			||||||
ASSERT_REG_POSITION(zeta_enable, 0x54E);
 | 
					ASSERT_REG_POSITION(zeta_enable, 0x54E);
 | 
				
			||||||
 | 
				
			|||||||
@ -257,7 +257,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MacroInterpreter::Send(u32 value) {
 | 
					void MacroInterpreter::Send(u32 value) {
 | 
				
			||||||
    maxwell3d.CallMethod({method_address.address, value});
 | 
					    maxwell3d.CallMethodFromMME({method_address.address, value});
 | 
				
			||||||
    // Increment the method address by the method increment.
 | 
					    // Increment the method address by the method increment.
 | 
				
			||||||
    method_address.address.Assign(method_address.address.Value() +
 | 
					    method_address.address.Assign(method_address.address.Value() +
 | 
				
			||||||
                                  method_address.increment.Value());
 | 
					                                  method_address.increment.Value());
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,10 @@ public:
 | 
				
			|||||||
    virtual ~RasterizerInterface() {}
 | 
					    virtual ~RasterizerInterface() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Draw the current batch of vertex arrays
 | 
					    /// Draw the current batch of vertex arrays
 | 
				
			||||||
    virtual void DrawArrays() = 0;
 | 
					    virtual bool DrawBatch(bool is_indexed) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Draw the current batch of multiple instances of vertex arrays
 | 
				
			||||||
 | 
					    virtual bool DrawMultiBatch(bool is_indexed) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Clear the current framebuffer
 | 
					    /// Clear the current framebuffer
 | 
				
			||||||
    virtual void Clear() = 0;
 | 
					    virtual void Clear() = 0;
 | 
				
			||||||
@ -69,10 +72,6 @@ public:
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual bool AccelerateDrawBatch(bool is_indexed) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Increase/decrease the number of object in pages touching the specified region
 | 
					    /// Increase/decrease the number of object in pages touching the specified region
 | 
				
			||||||
    virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
 | 
					    virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -49,40 +49,6 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192));
 | 
				
			|||||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
 | 
					MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
 | 
				
			||||||
MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100));
 | 
					MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DrawParameters {
 | 
					 | 
				
			||||||
    GLenum primitive_mode;
 | 
					 | 
				
			||||||
    GLsizei count;
 | 
					 | 
				
			||||||
    GLint current_instance;
 | 
					 | 
				
			||||||
    bool use_indexed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    GLint vertex_first;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    GLenum index_format;
 | 
					 | 
				
			||||||
    GLint base_vertex;
 | 
					 | 
				
			||||||
    GLintptr index_buffer_offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void DispatchDraw() const {
 | 
					 | 
				
			||||||
        if (use_indexed) {
 | 
					 | 
				
			||||||
            const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
 | 
					 | 
				
			||||||
            if (current_instance > 0) {
 | 
					 | 
				
			||||||
                glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
 | 
					 | 
				
			||||||
                                                              index_buffer_ptr, 1, base_vertex,
 | 
					 | 
				
			||||||
                                                              current_instance);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
 | 
					 | 
				
			||||||
                                         base_vertex);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            if (current_instance > 0) {
 | 
					 | 
				
			||||||
                glDrawArraysInstancedBaseInstance(primitive_mode, vertex_first, count, 1,
 | 
					 | 
				
			||||||
                                                  current_instance);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                glDrawArrays(primitive_mode, vertex_first, count);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
 | 
					static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
 | 
				
			||||||
                                      const GLShader::ConstBufferEntry& entry) {
 | 
					                                      const GLShader::ConstBufferEntry& entry) {
 | 
				
			||||||
    if (!entry.IsIndirect()) {
 | 
					    if (!entry.IsIndirect()) {
 | 
				
			||||||
@ -270,29 +236,6 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
 | 
				
			|||||||
    return offset;
 | 
					    return offset;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DrawParameters RasterizerOpenGL::SetupDraw(GLintptr index_buffer_offset) {
 | 
					 | 
				
			||||||
    const auto& gpu = system.GPU().Maxwell3D();
 | 
					 | 
				
			||||||
    const auto& regs = gpu.regs;
 | 
					 | 
				
			||||||
    const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DrawParameters params{};
 | 
					 | 
				
			||||||
    params.current_instance = gpu.state.current_instance;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    params.use_indexed = is_indexed;
 | 
					 | 
				
			||||||
    params.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (is_indexed) {
 | 
					 | 
				
			||||||
        params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
 | 
					 | 
				
			||||||
        params.count = regs.index_array.count;
 | 
					 | 
				
			||||||
        params.index_buffer_offset = index_buffer_offset;
 | 
					 | 
				
			||||||
        params.base_vertex = static_cast<GLint>(regs.vb_element_base);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        params.count = regs.vertex_buffer.count;
 | 
					 | 
				
			||||||
        params.vertex_first = regs.vertex_buffer.first;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return params;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
 | 
					void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
 | 
				
			||||||
    MICROPROFILE_SCOPE(OpenGL_Shader);
 | 
					    MICROPROFILE_SCOPE(OpenGL_Shader);
 | 
				
			||||||
    auto& gpu = system.GPU().Maxwell3D();
 | 
					    auto& gpu = system.GPU().Maxwell3D();
 | 
				
			||||||
@ -399,12 +342,6 @@ std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const {
 | 
				
			|||||||
           static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
 | 
					           static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
 | 
					 | 
				
			||||||
    accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
 | 
					 | 
				
			||||||
    DrawArrays();
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Map, typename Interval>
 | 
					template <typename Map, typename Interval>
 | 
				
			||||||
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
 | 
					static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
 | 
				
			||||||
    return boost::make_iterator_range(map.equal_range(interval));
 | 
					    return boost::make_iterator_range(map.equal_range(interval));
 | 
				
			||||||
@ -640,17 +577,9 @@ void RasterizerOpenGL::Clear() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RasterizerOpenGL::DrawArrays() {
 | 
					void RasterizerOpenGL::DrawPrelude() {
 | 
				
			||||||
    if (accelerate_draw == AccelDraw::Disabled)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    MICROPROFILE_SCOPE(OpenGL_Drawing);
 | 
					 | 
				
			||||||
    auto& gpu = system.GPU().Maxwell3D();
 | 
					    auto& gpu = system.GPU().Maxwell3D();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!gpu.ShouldExecute()) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SyncColorMask();
 | 
					    SyncColorMask();
 | 
				
			||||||
    SyncFragmentColorClampState();
 | 
					    SyncFragmentColorClampState();
 | 
				
			||||||
    SyncMultiSampleState();
 | 
					    SyncMultiSampleState();
 | 
				
			||||||
@ -695,10 +624,7 @@ void RasterizerOpenGL::DrawArrays() {
 | 
				
			|||||||
    // Upload vertex and index data.
 | 
					    // Upload vertex and index data.
 | 
				
			||||||
    SetupVertexBuffer(vao);
 | 
					    SetupVertexBuffer(vao);
 | 
				
			||||||
    SetupVertexInstances(vao);
 | 
					    SetupVertexInstances(vao);
 | 
				
			||||||
    const GLintptr index_buffer_offset = SetupIndexBuffer();
 | 
					    index_buffer_offset = SetupIndexBuffer();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Setup draw parameters. It will automatically choose what glDraw* method to use.
 | 
					 | 
				
			||||||
    const DrawParameters params = SetupDraw(index_buffer_offset);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Prepare packed bindings.
 | 
					    // Prepare packed bindings.
 | 
				
			||||||
    bind_ubo_pushbuffer.Setup(0);
 | 
					    bind_ubo_pushbuffer.Setup(0);
 | 
				
			||||||
@ -706,7 +632,8 @@ void RasterizerOpenGL::DrawArrays() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Setup shaders and their used resources.
 | 
					    // Setup shaders and their used resources.
 | 
				
			||||||
    texture_cache.GuardSamplers(true);
 | 
					    texture_cache.GuardSamplers(true);
 | 
				
			||||||
    SetupShaders(params.primitive_mode);
 | 
					    const auto primitive_mode = MaxwellToGL::PrimitiveTopology(gpu.regs.draw.topology);
 | 
				
			||||||
 | 
					    SetupShaders(primitive_mode);
 | 
				
			||||||
    texture_cache.GuardSamplers(false);
 | 
					    texture_cache.GuardSamplers(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ConfigureFramebuffers();
 | 
					    ConfigureFramebuffers();
 | 
				
			||||||
@ -730,11 +657,107 @@ void RasterizerOpenGL::DrawArrays() {
 | 
				
			|||||||
    if (texture_cache.TextureBarrier()) {
 | 
					    if (texture_cache.TextureBarrier()) {
 | 
				
			||||||
        glTextureBarrier();
 | 
					        glTextureBarrier();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params.DispatchDraw();
 | 
					struct DrawParams {
 | 
				
			||||||
 | 
					    bool is_indexed{};
 | 
				
			||||||
 | 
					    bool is_instanced{};
 | 
				
			||||||
 | 
					    GLenum primitive_mode{};
 | 
				
			||||||
 | 
					    GLint count{};
 | 
				
			||||||
 | 
					    GLint base_vertex{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Indexed settings
 | 
				
			||||||
 | 
					    GLenum index_format{};
 | 
				
			||||||
 | 
					    GLintptr index_buffer_offset{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Instanced setting
 | 
				
			||||||
 | 
					    GLint num_instances{};
 | 
				
			||||||
 | 
					    GLint base_instance{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void DispatchDraw() {
 | 
				
			||||||
 | 
					        if (is_indexed) {
 | 
				
			||||||
 | 
					            const auto index_buffer_ptr = reinterpret_cast<const void*>(index_buffer_offset);
 | 
				
			||||||
 | 
					            if (is_instanced) {
 | 
				
			||||||
 | 
					                glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, count, index_format,
 | 
				
			||||||
 | 
					                                                              index_buffer_ptr, num_instances,
 | 
				
			||||||
 | 
					                                                              base_vertex, base_instance);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                glDrawElementsBaseVertex(primitive_mode, count, index_format, index_buffer_ptr,
 | 
				
			||||||
 | 
					                                         base_vertex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (is_instanced) {
 | 
				
			||||||
 | 
					                glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, count, num_instances,
 | 
				
			||||||
 | 
					                                                  base_instance);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                glDrawArrays(primitive_mode, base_vertex, count);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RasterizerOpenGL::DrawBatch(bool is_indexed) {
 | 
				
			||||||
 | 
					    accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MICROPROFILE_SCOPE(OpenGL_Drawing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DrawPrelude();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& maxwell3d = system.GPU().Maxwell3D();
 | 
				
			||||||
 | 
					    const auto& regs = maxwell3d.regs;
 | 
				
			||||||
 | 
					    const auto current_instance = maxwell3d.state.current_instance;
 | 
				
			||||||
 | 
					    DrawParams draw_call{};
 | 
				
			||||||
 | 
					    draw_call.is_indexed = is_indexed;
 | 
				
			||||||
 | 
					    draw_call.num_instances = static_cast<GLint>(1);
 | 
				
			||||||
 | 
					    draw_call.base_instance = static_cast<GLint>(current_instance);
 | 
				
			||||||
 | 
					    draw_call.is_instanced = current_instance > 0;
 | 
				
			||||||
 | 
					    draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
 | 
				
			||||||
 | 
					    if (draw_call.is_indexed) {
 | 
				
			||||||
 | 
					        draw_call.count = static_cast<GLint>(regs.index_array.count);
 | 
				
			||||||
 | 
					        draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
 | 
				
			||||||
 | 
					        draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
 | 
				
			||||||
 | 
					        draw_call.index_buffer_offset = index_buffer_offset;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
 | 
				
			||||||
 | 
					        draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    draw_call.DispatchDraw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    maxwell3d.dirty.memory_general = false;
 | 
				
			||||||
    accelerate_draw = AccelDraw::Disabled;
 | 
					    accelerate_draw = AccelDraw::Disabled;
 | 
				
			||||||
    gpu.dirty.memory_general = false;
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool RasterizerOpenGL::DrawMultiBatch(bool is_indexed) {
 | 
				
			||||||
 | 
					    accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MICROPROFILE_SCOPE(OpenGL_Drawing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DrawPrelude();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& maxwell3d = system.GPU().Maxwell3D();
 | 
				
			||||||
 | 
					    const auto& regs = maxwell3d.regs;
 | 
				
			||||||
 | 
					    const auto& draw_setup = maxwell3d.mme_draw;
 | 
				
			||||||
 | 
					    DrawParams draw_call{};
 | 
				
			||||||
 | 
					    draw_call.is_indexed = is_indexed;
 | 
				
			||||||
 | 
					    draw_call.num_instances = static_cast<GLint>(draw_setup.instance_count);
 | 
				
			||||||
 | 
					    draw_call.base_instance = static_cast<GLint>(regs.vb_base_instance);
 | 
				
			||||||
 | 
					    draw_call.is_instanced = draw_setup.instance_count > 1;
 | 
				
			||||||
 | 
					    draw_call.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
 | 
				
			||||||
 | 
					    if (draw_call.is_indexed) {
 | 
				
			||||||
 | 
					        draw_call.count = static_cast<GLint>(regs.index_array.count);
 | 
				
			||||||
 | 
					        draw_call.base_vertex = static_cast<GLint>(regs.vb_element_base);
 | 
				
			||||||
 | 
					        draw_call.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
 | 
				
			||||||
 | 
					        draw_call.index_buffer_offset = index_buffer_offset;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        draw_call.count = static_cast<GLint>(regs.vertex_buffer.count);
 | 
				
			||||||
 | 
					        draw_call.base_vertex = static_cast<GLint>(regs.vertex_buffer.first);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    draw_call.DispatchDraw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    maxwell3d.dirty.memory_general = false;
 | 
				
			||||||
 | 
					    accelerate_draw = AccelDraw::Disabled;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
 | 
					void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,8 @@ public:
 | 
				
			|||||||
                              ScreenInfo& info);
 | 
					                              ScreenInfo& info);
 | 
				
			||||||
    ~RasterizerOpenGL() override;
 | 
					    ~RasterizerOpenGL() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DrawArrays() override;
 | 
					    bool DrawBatch(bool is_indexed) override;
 | 
				
			||||||
 | 
					    bool DrawMultiBatch(bool is_indexed) override;
 | 
				
			||||||
    void Clear() override;
 | 
					    void Clear() override;
 | 
				
			||||||
    void DispatchCompute(GPUVAddr code_addr) override;
 | 
					    void DispatchCompute(GPUVAddr code_addr) override;
 | 
				
			||||||
    void FlushAll() override;
 | 
					    void FlushAll() override;
 | 
				
			||||||
@ -71,7 +72,6 @@ public:
 | 
				
			|||||||
                               const Tegra::Engines::Fermi2D::Config& copy_config) override;
 | 
					                               const Tegra::Engines::Fermi2D::Config& copy_config) override;
 | 
				
			||||||
    bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
 | 
					    bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
 | 
				
			||||||
                           u32 pixel_stride) override;
 | 
					                           u32 pixel_stride) override;
 | 
				
			||||||
    bool AccelerateDrawBatch(bool is_indexed) override;
 | 
					 | 
				
			||||||
    void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
 | 
					    void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
 | 
				
			||||||
    void LoadDiskResources(const std::atomic_bool& stop_loading,
 | 
					    void LoadDiskResources(const std::atomic_bool& stop_loading,
 | 
				
			||||||
                           const VideoCore::DiskResourceLoadCallback& callback) override;
 | 
					                           const VideoCore::DiskResourceLoadCallback& callback) override;
 | 
				
			||||||
@ -105,6 +105,9 @@ private:
 | 
				
			|||||||
    void SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entry, GPUVAddr gpu_addr,
 | 
					    void SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entry, GPUVAddr gpu_addr,
 | 
				
			||||||
                           std::size_t size);
 | 
					                           std::size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Syncs all the state, shaders, render targets and textures setting before a draw call.
 | 
				
			||||||
 | 
					    void DrawPrelude();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Configures the current textures to use for the draw command. Returns shaders texture buffer
 | 
					    /// Configures the current textures to use for the draw command. Returns shaders texture buffer
 | 
				
			||||||
    /// usage.
 | 
					    /// usage.
 | 
				
			||||||
    TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
 | 
					    TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
 | 
				
			||||||
@ -216,7 +219,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GLintptr SetupIndexBuffer();
 | 
					    GLintptr SetupIndexBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DrawParameters SetupDraw(GLintptr index_buffer_offset);
 | 
					    GLintptr index_buffer_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void SetupShaders(GLenum primitive_mode);
 | 
					    void SetupShaders(GLenum primitive_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -462,6 +462,14 @@ private:
 | 
				
			|||||||
            code.AddLine("float gl_PointSize;");
 | 
					            code.AddLine("float gl_PointSize;");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ir.UsesInstanceId()) {
 | 
				
			||||||
 | 
					            code.AddLine("int gl_InstanceID;");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ir.UsesVertexId()) {
 | 
				
			||||||
 | 
					            code.AddLine("int gl_VertexID;");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        --code.scope;
 | 
					        --code.scope;
 | 
				
			||||||
        code.AddLine("}};");
 | 
					        code.AddLine("}};");
 | 
				
			||||||
        code.AddNewLine();
 | 
					        code.AddNewLine();
 | 
				
			||||||
@ -964,7 +972,7 @@ private:
 | 
				
			|||||||
            switch (element) {
 | 
					            switch (element) {
 | 
				
			||||||
            case 2:
 | 
					            case 2:
 | 
				
			||||||
                // Config pack's first value is instance_id.
 | 
					                // Config pack's first value is instance_id.
 | 
				
			||||||
                return {"config_pack[0]", Type::Uint};
 | 
					                return {"gl_InstanceID", Type::Int};
 | 
				
			||||||
            case 3:
 | 
					            case 3:
 | 
				
			||||||
                return {"gl_VertexID", Type::Int};
 | 
					                return {"gl_VertexID", Type::Int};
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -114,6 +114,18 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (index == Attribute::Index::TessCoordInstanceIDVertexID) {
 | 
				
			||||||
 | 
					        switch (element) {
 | 
				
			||||||
 | 
					        case 2:
 | 
				
			||||||
 | 
					            uses_instance_id = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 3:
 | 
				
			||||||
 | 
					            uses_vertex_id = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (index == Attribute::Index::ClipDistances0123 ||
 | 
					    if (index == Attribute::Index::ClipDistances0123 ||
 | 
				
			||||||
        index == Attribute::Index::ClipDistances4567) {
 | 
					        index == Attribute::Index::ClipDistances4567) {
 | 
				
			||||||
        const auto clip_index =
 | 
					        const auto clip_index =
 | 
				
			||||||
 | 
				
			|||||||
@ -124,6 +124,14 @@ public:
 | 
				
			|||||||
        return uses_point_size;
 | 
					        return uses_point_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool UsesInstanceId() const {
 | 
				
			||||||
 | 
					        return uses_instance_id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool UsesVertexId() const {
 | 
				
			||||||
 | 
					        return uses_vertex_id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool HasPhysicalAttributes() const {
 | 
					    bool HasPhysicalAttributes() const {
 | 
				
			||||||
        return uses_physical_attributes;
 | 
					        return uses_physical_attributes;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -373,6 +381,8 @@ private:
 | 
				
			|||||||
    bool uses_viewport_index{};
 | 
					    bool uses_viewport_index{};
 | 
				
			||||||
    bool uses_point_size{};
 | 
					    bool uses_point_size{};
 | 
				
			||||||
    bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
 | 
					    bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
 | 
				
			||||||
 | 
					    bool uses_instance_id{};
 | 
				
			||||||
 | 
					    bool uses_vertex_id{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Tegra::Shader::Header header;
 | 
					    Tegra::Shader::Header header;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user