blob: d069e1c3732d1bd5c661400b843e82594ded51d9 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "context.h"
#include "gfx_api.h"
#include "interpreter.h"
#include "memory_manager.h"
#include "post_buffer.h"
#include "renderer.h"
#include "replay_request.h"
#include "resource_provider.h"
#include "resource_in_memory_cache.h"
#include "server_connection.h"
#include "stack.h"
#include <gapic/log.h>
#include <gapic/target.h>
#include <cstdlib>
#include <sstream>
#include <string>
namespace gapir {
std::unique_ptr<Context> Context::create(const ServerConnection& gazer,
ResourceProvider* resourceProvider,
MemoryManager* memoryManager) {
std::unique_ptr<Context> context(new Context(gazer, resourceProvider, memoryManager));
if (context->initialize()) {
return context;
} else {
return nullptr;
}
}
// TODO: Make the PostBuffer size dynamic? It currently holds 2MB of data.
Context::Context(const ServerConnection& gazer, ResourceProvider* resourceProvider,
MemoryManager* memoryManager) :
mServer(gazer), mResourceProvider(resourceProvider), mMemoryManager(memoryManager),
mBoundRenderer(nullptr),
mPostBuffer(new PostBuffer(POST_BUFFER_SIZE, [this](const void* address, uint32_t count) {
return this->mServer.post(address, count);
})) {
}
Context::~Context() {
for (auto it = mRenderers.begin(); it != mRenderers.end(); it++) {
delete it->second;
}
}
bool Context::initialize() {
mReplayRequest = ReplayRequest::create(mServer, mResourceProvider, mMemoryManager);
if (mReplayRequest == nullptr) {
return false;
}
if (!mMemoryManager->setVolatileMemory(mReplayRequest->getVolatileMemorySize())) {
GAPID_WARNING("Setting the volatile memory size failed (size: %u)",
mReplayRequest->getVolatileMemorySize());
return false;
}
mMemoryManager->setConstantMemory(mReplayRequest->getConstantMemory());
return true;
}
void Context::prefetch(ResourceInMemoryCache* cache) const {
auto cacheSize = static_cast<uint32_t>(
static_cast<uint8_t*>(mMemoryManager->getVolatileAddress()) -
static_cast<uint8_t*>(mMemoryManager->getBaseAddress()));
cache->resize(cacheSize);
auto resources = mReplayRequest->getResources();
if (resources.size() > 0) {
GAPID_INFO("Prefetching resources...");
mResourceProvider->prefetch(&resources[0], resources.size(), mServer,
mMemoryManager->getVolatileAddress(),
mReplayRequest->getVolatileMemorySize());
GAPID_INFO("Prefetching ready");
}
}
bool Context::interpret() {
Interpreter interpreter(mMemoryManager, mReplayRequest->getStackSize());
registerCallbacks(&interpreter);
return interpreter.run(mReplayRequest->getInstructionList()) && mPostBuffer->flush();
}
void Context::registerCallbacks(Interpreter* interpreter) {
// Custom function for posting and fetching resources to and from the server
interpreter->registerBuiltin(Interpreter::POST_FUNCTION_ID,
[this](Stack* stack, bool) { return this->postData(stack); });
interpreter->registerBuiltin(Interpreter::RESOURCE_FUNCTION_ID,
[this](Stack* stack, bool) { return this->loadResource(stack); });
// Registering custom synthetic functions
interpreter->registerBuiltin(Builtins::StartTimer,
[this](Stack* stack, bool) { return this->startTimer(stack); });
interpreter->registerBuiltin(Builtins::StopTimer,
[this](Stack* stack, bool pushReturn) {
return this->stopTimer(stack, pushReturn);
});
interpreter->registerBuiltin(Builtins::FlushPostBuffer, [this](Stack* stack, bool) {
return this->flushPostBuffer(stack);
});
interpreter->registerBuiltin(Builtins::ReplayCreateRenderer, [this](Stack* stack, bool) {
uint32_t id = stack->pop<uint32_t>();
if (stack->isValid()) {
GAPID_INFO("replayCreateRenderer(%u)", id);
if (Renderer* prev = mRenderers[id]) {
if (mBoundRenderer == prev) {
mBoundRenderer = nullptr;
}
delete prev;
}
mRenderers[id] = Renderer::create();
return true;
} else {
GAPID_WARNING("Error during calling function replayCreateRenderer");
return false;
}
});
interpreter->registerBuiltin(Builtins::ReplayBindRenderer, [this, interpreter](Stack* stack, bool) {
uint32_t id = stack->pop<uint32_t>();
if (stack->isValid()) {
if (mBoundRenderer != nullptr) {
mBoundRenderer->unbind();
mBoundRenderer = nullptr;
}
mBoundRenderer = mRenderers[id];
mBoundRenderer->bind();
Api* api = mBoundRenderer->api();
interpreter->setRendererFunctions(&api->mFunctions);
GAPID_INFO("Bound renderer %u: %s - %s", id, mBoundRenderer->name(), mBoundRenderer->version());
return true;
} else {
GAPID_WARNING("Error during calling function replayBindRenderer");
return false;
}
});
interpreter->registerBuiltin(Builtins::ContextInfo, [this](Stack* stack, bool) {
Renderer::Backbuffer backbuffer;
bool preserveBuffersOnSwap = stack->pop<bool>();
bool resetViewportScissor = stack->pop<bool>();
backbuffer.format.stencil = stack->pop<uint32_t>();
backbuffer.format.depth = stack->pop<uint32_t>();
backbuffer.format.color = stack->pop<uint32_t>();
backbuffer.height = stack->pop<int32_t>();
backbuffer.width = stack->pop<int32_t>();
const uint8_t* constant_data = stack->pop<uint8_t*>();
const uint32_t* constant_sizes = stack->pop<uint32_t*>();
const uint32_t* constant_offsets = stack->pop<uint32_t*>();
const uint32_t* constant_names = stack->pop<uint32_t*>();
const uint32_t constant_count = stack->pop<uint32_t>();
if (!stack->isValid()) {
GAPID_WARNING("Error during calling function replayCreateRenderer");
return false;
}
if (stack->isValid()) {
GAPID_INFO("contextInfo(%d, %d, 0x%x, 0x%x, 0x%x)",
backbuffer.width,
backbuffer.height,
backbuffer.format.color,
backbuffer.format.depth,
backbuffer.format.stencil,
resetViewportScissor ? "true" : "false");
if (mBoundRenderer == nullptr) {
GAPID_INFO("contextInfo called without a bound renderer");
return false;
}
mBoundRenderer->setBackbuffer(backbuffer);
auto gles = mBoundRenderer->getApi<Gles>();
// TODO: This needs to change when we support other APIs.
GAPID_ASSERT(gles != nullptr);
if (resetViewportScissor) {
gles->glViewport(0, 0, backbuffer.width, backbuffer.height);
gles->glScissor(0, 0, backbuffer.width, backbuffer.height);
}
return true;
} else {
GAPID_WARNING("Error during calling function replayCreateRenderer");
return false;
}
});
}
bool Context::loadResource(Stack* stack) {
uint32_t resourceId = stack->pop<uint32_t>();
void* address = stack->pop<void*>();
if (!stack->isValid()) {
GAPID_WARNING("Error during loadResource");
return false;
}
const auto& resource = mReplayRequest->getResources()[resourceId];
if (!mResourceProvider->get(&resource, 1, mServer, address, resource.size)) {
GAPID_WARNING("Can't fetch resource: %s", resource.id.c_str());
return false;
}
return true;
}
bool Context::postData(Stack* stack) {
const uint32_t count = stack->pop<uint32_t>();
const void* address = stack->pop<const void*>();
if (!stack->isValid()) {
GAPID_WARNING("Error during postData");
return false;
}
return mPostBuffer->push(address, count);
}
bool Context::flushPostBuffer(Stack* stack) {
if (!stack->isValid()) {
GAPID_WARNING("Error during flushPostBuffer");
return false;
}
return mPostBuffer->flush();
}
bool Context::startTimer(Stack* stack) {
size_t index = static_cast<size_t>(stack->pop<uint8_t>());
if (stack->isValid()) {
if (index < MAX_TIMERS) {
GAPID_INFO("startTimer(%d)", index);
mTimers[index].Start();
return true;
} else {
GAPID_WARNING("StartTimer called with invalid index %d", index);
}
} else {
GAPID_WARNING("Error while calling function StartTimer");
}
return false;
}
bool Context::stopTimer(Stack* stack, bool pushReturn) {
size_t index = static_cast<size_t>(stack->pop<uint8_t>());
if (stack->isValid()) {
if (index < MAX_TIMERS) {
GAPID_INFO("stopTimer(%d)", index);
uint64_t ns = mTimers[index].Stop();
if (pushReturn) {
stack->push(ns);
}
return true;
} else {
GAPID_WARNING("StopTimer called with invalid index %d", index);
}
} else {
GAPID_WARNING("Error while calling function StopTimer");
}
return false;
}
} // namespace gapir