blob: 390c75aabe971d2ee68c38537c8cc1081342d745 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "engine_command_streamer.h"
#include "cache_config.h"
#include "device_id.h"
#include "instructions.h"
#include "magma_util/macros.h"
#include "msd_intel_buffer.h"
#include "msd_intel_connection.h"
#include "platform_trace.h"
#include "registers.h"
#include "render_init_batch.h"
#include "ringbuffer.h"
#include <thread>
EngineCommandStreamer::EngineCommandStreamer(Owner* owner, EngineCommandStreamerId id,
uint32_t mmio_base)
: owner_(owner), id_(id), mmio_base_(mmio_base)
{
DASSERT(owner);
}
bool EngineCommandStreamer::InitContext(MsdIntelContext* context) const
{
DASSERT(context);
uint32_t context_size = GetContextSize();
DASSERT(context_size > 0 && magma::is_page_aligned(context_size));
std::unique_ptr<MsdIntelBuffer> context_buffer(
MsdIntelBuffer::Create(context_size, "context-buffer"));
if (!context_buffer)
return DRETF(false, "couldn't create context buffer");
std::unique_ptr<Ringbuffer> ringbuffer(
new Ringbuffer(MsdIntelBuffer::Create(32 * PAGE_SIZE, "ring-buffer")));
if (!InitContextBuffer(context_buffer.get(), ringbuffer.get(),
context->exec_address_space().get()))
return DRETF(false, "InitContextBuffer failed");
// Transfer ownership of context_buffer
context->SetEngineState(id(), std::move(context_buffer), std::move(ringbuffer));
return true;
}
bool EngineCommandStreamer::InitContextCacheConfig(MsdIntelContext* context)
{
auto ringbuffer = context->get_ringbuffer(id());
if (!ringbuffer->HasSpace(CacheConfig::InstructionBytesRequired()))
return DRETF(false, "insufficient ringbuffer space for cache config");
if (!CacheConfig::InitCacheConfig(ringbuffer, id()))
return DRETF(false, "failed to init cache config buffer");
return true;
}
void EngineCommandStreamer::InitHardware()
{
Reset();
HardwareStatusPage* status_page = hardware_status_page(id());
registers::HardwareStatusPageAddress::write(register_io(), mmio_base_, status_page->gpu_addr());
uint32_t initial_sequence_number = sequencer()->next_sequence_number();
status_page->write_sequence_number(initial_sequence_number);
DLOG("initialized engine sequence number: 0x%x", initial_sequence_number);
registers::GraphicsMode::write(register_io(), mmio_base_,
registers::GraphicsMode::kExeclistEnable,
registers::GraphicsMode::kExeclistEnable);
registers::HardwareStatusMask::write(
register_io(), mmio_base_, registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::USER, registers::InterruptRegisterBase::UNMASK);
registers::GtInterruptMask0::write(
register_io(), registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::USER, registers::InterruptRegisterBase::UNMASK);
registers::GtInterruptEnable0::write(register_io(),
registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::USER, true);
registers::HardwareStatusMask::write(
register_io(), mmio_base_, registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::CONTEXT_SWITCH, registers::InterruptRegisterBase::UNMASK);
registers::GtInterruptMask0::write(
register_io(), registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::CONTEXT_SWITCH, registers::InterruptRegisterBase::UNMASK);
registers::GtInterruptEnable0::write(register_io(),
registers::InterruptRegisterBase::RENDER_ENGINE,
registers::InterruptRegisterBase::CONTEXT_SWITCH, true);
// WaEnableGapsTsvCreditFix
registers::ArbiterControl::workaround(register_io());
}
void EngineCommandStreamer::InvalidateTlbs()
{
// Should only be called when gpu is idle.
switch (id()) {
case RENDER_COMMAND_STREAMER: {
auto reg = registers::RenderEngineTlbControl::Get().FromValue(0);
reg.invalidate().set(1);
reg.WriteTo(register_io());
break;
}
default:
DASSERT(false);
break;
}
}
// Register definitions from BSpec BXML Reference.
// Register State Context definition from public BSpec,
// intel-gfx-prm-osrc-bdw-vol07-3d_media_gpgpu_3.pdf pp. 27-28
class RegisterStateHelper {
public:
RegisterStateHelper(EngineCommandStreamerId id, uint32_t mmio_base, uint32_t* state)
: id_(id), mmio_base_(mmio_base), state_(state)
{
}
void write_load_register_immediate_headers()
{
switch (id_) {
case RENDER_COMMAND_STREAMER:
state_[1] = 0x1100101B;
state_[0x21] = 0x11001011;
state_[0x41] = 0x11000001;
break;
}
}
// CTXT_SR_CTL - Context Save/Restore Control Register
void write_context_save_restore_control()
{
constexpr uint32_t kInhibitSyncContextSwitchBit = 1 << 3;
constexpr uint32_t kRenderContextRestoreInhibitBit = 1;
state_[2] = mmio_base_ + 0x244;
if (id_ == RENDER_COMMAND_STREAMER) {
uint32_t bits = kInhibitSyncContextSwitchBit | kRenderContextRestoreInhibitBit;
state_[3] = (bits << 16) | bits;
}
}
// RING_BUFFER_HEAD - Ring Buffer Head
void write_ring_head_pointer(uint32_t head)
{
state_[4] = mmio_base_ + 0x34;
state_[5] = head;
}
// RING_BUFFER_TAIL - Ring Buffer Tail
void write_ring_tail_pointer(uint32_t tail)
{
state_[6] = mmio_base_ + 0x30;
state_[7] = tail;
}
// RING_BUFFER_START - Ring Buffer Start
void write_ring_buffer_start(uint32_t ring_buffer_start)
{
state_[8] = mmio_base_ + 0x38;
state_[9] = ring_buffer_start;
}
// RING_BUFFER_CTL - Ring Buffer Control
void write_ring_buffer_control(uint32_t ringbuffer_size)
{
constexpr uint32_t kRingValid = 1;
DASSERT(ringbuffer_size >= PAGE_SIZE && ringbuffer_size <= 512 * PAGE_SIZE);
DASSERT(magma::is_page_aligned(ringbuffer_size));
state_[0xA] = mmio_base_ + 0x3C;
// This register assumes 4k pages
DASSERT(PAGE_SIZE == 4096);
state_[0xB] = (ringbuffer_size - PAGE_SIZE) | kRingValid;
}
// BB_ADDR_UDW - Batch Buffer Upper Head Pointer Register
void write_batch_buffer_upper_head_pointer()
{
state_[0xC] = mmio_base_ + 0x168;
state_[0xD] = 0;
}
// BB_ADDR - Batch Buffer Head Pointer Register
void write_batch_buffer_head_pointer()
{
state_[0xE] = mmio_base_ + 0x140;
state_[0xF] = 0;
}
// BB_STATE - Batch Buffer State Register
void write_batch_buffer_state()
{
constexpr uint32_t kAddressSpacePpgtt = 1 << 5;
state_[0x10] = mmio_base_ + 0x110;
state_[0x11] = kAddressSpacePpgtt;
}
// SBB_ADDR_UDW - Second Level Batch Buffer Upper Head Pointer Register
void write_second_level_batch_buffer_upper_head_pointer()
{
state_[0x12] = mmio_base_ + 0x11C;
state_[0x13] = 0;
}
// SBB_ADDR - Second Level Batch Buffer Head Pointer Register
void write_second_level_batch_buffer_head_pointer()
{
state_[0x14] = mmio_base_ + 0x114;
state_[0x15] = 0;
}
// SBB_STATE - Second Level Batch Buffer State Register
void write_second_level_batch_buffer_state()
{
state_[0x16] = mmio_base_ + 0x118;
state_[0x17] = 0;
}
// BB_PER_CTX_PTR - Batch Buffer Per Context Pointer
void write_batch_buffer_per_context_pointer()
{
state_[0x18] = mmio_base_ + 0x1C0;
state_[0x19] = 0;
}
// INDIRECT_CTX - Indirect Context Pointer
void write_indirect_context_pointer()
{
state_[0x1A] = mmio_base_ + 0x1C4;
state_[0x1B] = 0;
}
// INDIRECT_CTX_OFFSET - Indirect Context Offset Pointer
void write_indirect_context_offset_pointer()
{
state_[0x1C] = mmio_base_ + 0x1C8;
state_[0x1D] = 0;
}
// CS_CTX_TIMESTAMP - CS Context Timestamp Count
void write_context_timestamp()
{
state_[0x22] = mmio_base_ + 0x3A8;
state_[0x23] = 0;
}
void write_pdp3_upper(uint64_t pdp_bus_addr)
{
state_[0x24] = mmio_base_ + 0x28C;
state_[0x25] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp3_lower(uint64_t pdp_bus_addr)
{
state_[0x26] = mmio_base_ + 0x288;
state_[0x27] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp2_upper(uint64_t pdp_bus_addr)
{
state_[0x28] = mmio_base_ + 0x284;
state_[0x29] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp2_lower(uint64_t pdp_bus_addr)
{
state_[0x2A] = mmio_base_ + 0x280;
state_[0x2B] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp1_upper(uint64_t pdp_bus_addr)
{
state_[0x2C] = mmio_base_ + 0x27C;
state_[0x2D] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp1_lower(uint64_t pdp_bus_addr)
{
state_[0x2E] = mmio_base_ + 0x278;
state_[0x2F] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp0_upper(uint64_t pdp_bus_addr)
{
state_[0x30] = mmio_base_ + 0x274;
state_[0x31] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp0_lower(uint64_t pdp_bus_addr)
{
state_[0x32] = mmio_base_ + 0x270;
state_[0x33] = magma::lower_32_bits(pdp_bus_addr);
}
// R_PWR_CLK_STATE - Render Power Clock State Register
void write_render_power_clock_state()
{
state_[0x42] = mmio_base_ + 0x0C8;
state_[0x43] = 0;
}
private:
EngineCommandStreamerId id_;
uint32_t mmio_base_;
uint32_t* state_;
};
bool EngineCommandStreamer::InitContextBuffer(MsdIntelBuffer* buffer, Ringbuffer* ringbuffer,
AddressSpace* address_space) const
{
auto platform_buf = buffer->platform_buffer();
void* addr;
if (!platform_buf->MapCpu(&addr))
return DRETF(false, "Couldn't map context buffer");
uint32_t* state = reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(addr) + PAGE_SIZE);
RegisterStateHelper helper(id(), mmio_base_, state);
helper.write_load_register_immediate_headers();
helper.write_context_save_restore_control();
helper.write_ring_head_pointer(ringbuffer->head());
// Ring buffer tail and start is patched in later (see UpdateContext).
helper.write_ring_tail_pointer(0);
helper.write_ring_buffer_start(~0);
helper.write_ring_buffer_control(ringbuffer->size());
helper.write_batch_buffer_upper_head_pointer();
helper.write_batch_buffer_head_pointer();
helper.write_batch_buffer_state();
helper.write_second_level_batch_buffer_upper_head_pointer();
helper.write_second_level_batch_buffer_head_pointer();
helper.write_second_level_batch_buffer_state();
helper.write_batch_buffer_per_context_pointer();
helper.write_indirect_context_pointer();
helper.write_indirect_context_offset_pointer();
helper.write_context_timestamp();
helper.write_pdp3_upper(0);
helper.write_pdp3_lower(0);
helper.write_pdp2_upper(0);
helper.write_pdp2_lower(0);
helper.write_pdp1_upper(0);
helper.write_pdp1_lower(0);
helper.write_pdp0_upper(0);
helper.write_pdp0_lower(0);
if (address_space->type() == ADDRESS_SPACE_PPGTT) {
auto ppgtt = static_cast<PerProcessGtt*>(address_space);
uint64_t pml4_addr = ppgtt->get_pml4_bus_addr();
helper.write_pdp0_upper(pml4_addr);
helper.write_pdp0_lower(pml4_addr);
}
if (id() == RENDER_COMMAND_STREAMER) {
helper.write_render_power_clock_state();
}
if (!platform_buf->UnmapCpu())
return DRETF(false, "Couldn't unmap context buffer");
return true;
}
bool EngineCommandStreamer::SubmitContext(MsdIntelContext* context, uint32_t tail)
{
TRACE_DURATION("magma", "SubmitContext");
if (!UpdateContext(context, tail))
return DRETF(false, "UpdateContext failed");
SubmitExeclists(context);
return true;
}
bool EngineCommandStreamer::UpdateContext(MsdIntelContext* context, uint32_t tail)
{
gpu_addr_t gpu_addr;
if (!context->GetRingbufferGpuAddress(id(), &gpu_addr))
return DRETF(false, "failed to get ringbuffer gpu address");
uint8_t* cpu_addr = reinterpret_cast<uint8_t*>(context->GetCachedContextBufferCpuAddr(id()));
if (!cpu_addr)
return DRETF(false, "failed to get cached context buffer cpu address");
RegisterStateHelper helper(id(), mmio_base_, reinterpret_cast<uint32_t*>(cpu_addr + PAGE_SIZE));
DLOG("UpdateContext ringbuffer gpu_addr 0x%lx tail 0x%x", gpu_addr, tail);
helper.write_ring_tail_pointer(tail);
helper.write_ring_buffer_start(gpu_addr);
return true;
}
void EngineCommandStreamer::SubmitExeclists(MsdIntelContext* context)
{
TRACE_DURATION("magma", "SubmitExeclists");
gpu_addr_t gpu_addr;
if (!context->GetGpuAddress(id(), &gpu_addr)) {
// Shouldn't happen.
DASSERT(false);
gpu_addr = kInvalidGpuAddr;
}
auto start = std::chrono::high_resolution_clock::now();
for (bool busy = true; busy;) {
constexpr uint32_t kTimeoutUs = 100;
uint64_t status = registers::ExeclistStatus::read(register_io(), mmio_base());
busy = registers::ExeclistStatus::execlist_write_pointer(status) ==
registers::ExeclistStatus::execlist_current_pointer(status) &&
registers::ExeclistStatus::execlist_queue_full(status);
if (busy) {
if (std::chrono::duration<double, std::micro>(
std::chrono::high_resolution_clock::now() - start)
.count() > kTimeoutUs) {
magma::log(magma::LOG_WARNING, "Timeout waiting for execlist port");
break;
}
}
}
DLOG("SubmitExeclists context descriptor id 0x%lx", gpu_addr >> 12);
// Use most significant bits of context gpu_addr as globally unique context id
DASSERT(PAGE_SIZE == 4096);
uint64_t descriptor0 = registers::ExeclistSubmitPort::context_descriptor(
gpu_addr, gpu_addr >> 12, context->exec_address_space()->type() == ADDRESS_SPACE_PPGTT);
uint64_t descriptor1 = 0;
registers::ExeclistSubmitPort::write(register_io(), mmio_base_, descriptor1, descriptor0);
}
uint64_t EngineCommandStreamer::GetActiveHeadPointer()
{
return registers::ActiveHeadPointer::read(register_io(), mmio_base_);
}
bool EngineCommandStreamer::Reset()
{
registers::GraphicsDeviceResetControl::Engine engine;
switch (id()) {
case RENDER_COMMAND_STREAMER:
engine = registers::GraphicsDeviceResetControl::RENDER_ENGINE;
break;
default:
return DRETF(false, "Reset for engine id %d not implemented", id());
}
registers::ResetControl::request(register_io(), mmio_base());
constexpr uint32_t kRetryMs = 10;
constexpr uint32_t kRetryTimeoutMs = 100;
auto start = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed;
bool ready_for_reset = false;
do {
ready_for_reset = registers::ResetControl::ready_for_reset(register_io(), mmio_base());
if (ready_for_reset) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(kRetryMs));
elapsed = std::chrono::high_resolution_clock::now() - start;
} while (elapsed.count() < kRetryTimeoutMs);
bool reset_complete = false;
if (ready_for_reset) {
registers::GraphicsDeviceResetControl::initiate_reset(register_io(), engine);
start = std::chrono::high_resolution_clock::now();
do {
reset_complete =
registers::GraphicsDeviceResetControl::is_reset_complete(register_io(), engine);
if (reset_complete) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(kRetryMs));
elapsed = std::chrono::high_resolution_clock::now() - start;
} while (elapsed.count() < kRetryTimeoutMs);
}
// Always invalidate tlbs, otherwise risk memory corruption.
InvalidateTlbs();
DLOG("ready_for_reset %d reset_complete %d", ready_for_reset, reset_complete);
return DRETF(reset_complete, "Reset did not complete");
}
///////////////////////////////////////////////////////////////////////////////
std::unique_ptr<RenderInitBatch>
RenderEngineCommandStreamer::CreateRenderInitBatch(uint32_t device_id)
{
std::unique_ptr<RenderInitBatch> batch;
if (DeviceId::is_gen9(device_id)) {
return std::unique_ptr<RenderInitBatch>(new RenderInitBatchGen9());
}
return DRETP(nullptr, "unhandled device id");
}
std::unique_ptr<RenderEngineCommandStreamer>
RenderEngineCommandStreamer::Create(EngineCommandStreamer::Owner* owner)
{
return std::unique_ptr<RenderEngineCommandStreamer>(new RenderEngineCommandStreamer(owner));
}
RenderEngineCommandStreamer::RenderEngineCommandStreamer(EngineCommandStreamer::Owner* owner)
: EngineCommandStreamer(owner, RENDER_COMMAND_STREAMER, kRenderEngineMmioBase)
{
scheduler_ = Scheduler::CreateFifoScheduler();
}
bool RenderEngineCommandStreamer::RenderInit(std::shared_ptr<MsdIntelContext> context,
std::unique_ptr<RenderInitBatch> init_batch,
std::shared_ptr<AddressSpace> address_space)
{
DASSERT(context);
DASSERT(init_batch);
DASSERT(address_space);
auto buffer = std::unique_ptr<MsdIntelBuffer>(
MsdIntelBuffer::Create(init_batch->size(), "render-init-batch"));
if (!buffer)
return DRETF(false, "failed to allocate render init buffer");
auto mapping = init_batch->Init(std::move(buffer), address_space);
if (!mapping)
return DRETF(false, "batch init failed");
std::unique_ptr<SimpleMappedBatch> mapped_batch(
new SimpleMappedBatch(context, std::move(mapping)));
return ExecBatch(std::move(mapped_batch));
}
bool RenderEngineCommandStreamer::ExecBatch(std::unique_ptr<MappedBatch> mapped_batch)
{
TRACE_DURATION("magma", "ExecBatch");
auto context = mapped_batch->GetContext().lock();
DASSERT(context);
if (!MoveBatchToInflight(std::move(mapped_batch)))
return DRETF(false, "WriteBatchToRingbuffer failed");
SubmitContext(context.get(), inflight_command_sequences_.back().ringbuffer_offset());
return true;
}
bool RenderEngineCommandStreamer::MoveBatchToInflight(std::unique_ptr<MappedBatch> mapped_batch)
{
auto context = mapped_batch->GetContext().lock();
DASSERT(context);
gpu_addr_t gpu_addr;
if (mapped_batch->GetGpuAddress(&gpu_addr)) {
if (!StartBatchBuffer(context.get(), gpu_addr, context->exec_address_space()->type()))
return DRETF(false, "failed to emit batch");
}
uint32_t sequence_number;
if (!PipeControl(context.get(), mapped_batch->GetPipeControlFlags(), &sequence_number))
return DRETF(false, "PipeControl failed");
auto ringbuffer = context->get_ringbuffer(id());
// TODO: don't allocate a sequence number if we don't have space for the user interrupt
if (!ringbuffer->HasSpace(MiUserInterrupt::kDwordCount * sizeof(uint32_t)))
return DRETF(false, "ringbuffer has insufficient space");
MiUserInterrupt::write(ringbuffer);
mapped_batch->SetSequenceNumber(sequence_number);
uint32_t ringbuffer_offset = context->get_ringbuffer(id())->tail();
inflight_command_sequences_.emplace(sequence_number, ringbuffer_offset,
std::move(mapped_batch));
batch_submitted(sequence_number);
return true;
}
void RenderEngineCommandStreamer::ContextSwitched()
{
context_switch_pending_ = false;
ScheduleContext();
}
void RenderEngineCommandStreamer::ScheduleContext()
{
auto context = scheduler_->ScheduleContext();
if (!context)
return;
while (true) {
auto mapped_batch = std::move(context->pending_batch_queue().front());
mapped_batch->scheduled();
context->pending_batch_queue().pop();
// TODO(MA-142) - MoveBatchToInflight should not fail. Scheduler should verify there is
// sufficient room in the ringbuffer before selecting a context.
// For now, drop the command buffer and try another context.
if (!MoveBatchToInflight(std::move(mapped_batch))) {
magma::log(magma::LOG_WARNING, "ExecBatch failed");
break;
}
// Scheduler returns nullptr when its time to switch contexts
auto next_context = scheduler_->ScheduleContext();
if (next_context == nullptr)
break;
DASSERT(context == next_context);
}
SubmitContext(context.get(), inflight_command_sequences_.back().ringbuffer_offset());
context_switch_pending_ = true;
}
void RenderEngineCommandStreamer::SubmitBatch(std::unique_ptr<MappedBatch> batch)
{
auto context = batch->GetContext().lock();
if (!context)
return;
context->pending_batch_queue().emplace(std::move(batch));
scheduler_->CommandBufferQueued(context);
if (!context_switch_pending_)
ScheduleContext();
}
bool RenderEngineCommandStreamer::WaitIdle()
{
constexpr uint32_t kTimeOutMs = 100;
uint32_t sequence_number = Sequencer::kInvalidSequenceNumber;
auto start = std::chrono::high_resolution_clock::now();
while (!inflight_command_sequences_.empty()) {
uint32_t last_completed_sequence_number =
hardware_status_page(RENDER_COMMAND_STREAMER)->read_sequence_number();
ProcessCompletedCommandBuffers(last_completed_sequence_number);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end - start;
if (last_completed_sequence_number != sequence_number) {
sequence_number = last_completed_sequence_number;
start = end;
} else if (elapsed.count() > kTimeOutMs) {
return DRETF(false, "WaitIdle timeout");
}
std::this_thread::yield();
}
return true;
}
void RenderEngineCommandStreamer::ProcessCompletedCommandBuffers(uint32_t last_completed_sequence)
{
// pop all completed command buffers
while (!inflight_command_sequences_.empty() &&
inflight_command_sequences_.front().sequence_number() <= last_completed_sequence) {
InflightCommandSequence& sequence = inflight_command_sequences_.front();
DLOG("ProcessCompletedCommandBuffers popping inflight command sequence with "
"sequence_number 0x%x "
"ringbuffer_start_offset 0x%x",
sequence.sequence_number(), sequence.ringbuffer_offset());
auto context = sequence.GetContext().lock();
DASSERT(context);
context->get_ringbuffer(id())->update_head(sequence.ringbuffer_offset());
if (sequence.mapped_batch()->was_scheduled())
scheduler_->CommandBufferCompleted(context);
inflight_command_sequences_.pop();
}
}
bool EngineCommandStreamer::PipeControl(MsdIntelContext* context, uint32_t flags,
uint32_t* sequence_number_out)
{
auto ringbuffer = context->get_ringbuffer(id());
uint32_t dword_count = MiPipeControl::kDwordCount + MiNoop::kDwordCount;
if (!ringbuffer->HasSpace(dword_count * sizeof(uint32_t)))
return DRETF(false, "ringbuffer has insufficient space");
gpu_addr_t gpu_addr =
hardware_status_page(id())->gpu_addr() + HardwareStatusPage::kSequenceNumberOffset;
uint32_t sequence_number = sequencer()->next_sequence_number();
DLOG("writing sequence number update to 0x%x", sequence_number);
MiPipeControl::write(ringbuffer, sequence_number, gpu_addr, flags);
MiNoop::write(ringbuffer);
*sequence_number_out = sequence_number;
return true;
}
bool RenderEngineCommandStreamer::StartBatchBuffer(MsdIntelContext* context, gpu_addr_t gpu_addr,
AddressSpaceType address_space_type)
{
auto ringbuffer = context->get_ringbuffer(id());
uint32_t dword_count = MiBatchBufferStart::kDwordCount + MiNoop::kDwordCount;
if (!ringbuffer->HasSpace(dword_count * sizeof(uint32_t)))
return DRETF(false, "ringbuffer has insufficient space");
MiBatchBufferStart::write(ringbuffer, gpu_addr, address_space_type);
MiNoop::write(ringbuffer);
DLOG("started batch buffer 0x%lx address_space_type %d", gpu_addr, address_space_type);
return true;
}
void RenderEngineCommandStreamer::ResetCurrentContext()
{
DLOG("ResetCurrentContext");
DASSERT(!inflight_command_sequences_.empty());
auto context = inflight_command_sequences_.front().GetContext().lock();
DASSERT(context);
// Cleanup resources for any inflight command sequences on this context
while (!inflight_command_sequences_.empty()) {
auto& sequence = inflight_command_sequences_.front();
if (sequence.mapped_batch()->was_scheduled())
scheduler_->CommandBufferCompleted(
inflight_command_sequences_.front().GetContext().lock());
inflight_command_sequences_.pop();
}
context->Kill();
// Reset the engine hardware
EngineCommandStreamer::Reset();
}
std::vector<MappedBatch*> RenderEngineCommandStreamer::GetInflightBatches()
{
uint32_t num_sequences = inflight_command_sequences_.size();
std::vector<MappedBatch*> inflight_batches;
inflight_batches.reserve(num_sequences);
for (uint32_t i = 0; i < num_sequences; i++) {
auto sequence = std::move(inflight_command_sequences_.front());
inflight_batches.push_back(sequence.mapped_batch());
// Pop off the front and push to the back
inflight_command_sequences_.pop();
inflight_command_sequences_.push(std::move(sequence));
}
return inflight_batches;
}