blob: 613fe98c4e03e89d978f8e9d0eefc6b8b0eaf849 [file] [log] [blame]
/*
* Copyright (C) 2015 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 "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)\n",
mReplayRequest->getVolatileMemorySize());
return false;
}
mMemoryManager->setConstantMemory(mReplayRequest->getConstantMemory());
GAPID_INFO("Prefetching resources...\n");
mResourceProvider->prefetch(mReplayRequest->getResources(), mServer,
mMemoryManager->getVolatileAddress(),
mReplayRequest->getVolatileMemorySize());
GAPID_INFO("Prefetching ready\n");
mInMemoryCacheSize = static_cast<uint32_t>(
static_cast<uint8_t*>(mMemoryManager->getVolatileAddress()) -
static_cast<uint8_t*>(mMemoryManager->getBaseAddress()));
return true;
}
bool Context::interpret() {
Interpreter interpreter(mMemoryManager, mReplayRequest->getStackSize());
registerCallbacks(&interpreter);
return interpreter.run(mReplayRequest->getInstructionList()) && mPostBuffer->flush();
}
uint32_t Context::getInMemoryCacheSize() const {
return mInMemoryCacheSize;
}
void Context::registerCallbacks(Interpreter* interpreter) {
gfxapi::Register(interpreter);
// Custom function for posting and fetching resources to and from the server
interpreter->registerFunction(Interpreter::POST_FUNCTION_ID,
[this](Stack* stack, bool) { return this->postData(stack); });
interpreter->registerFunction(Interpreter::RESOURCE_FUNCTION_ID,
[this](Stack* stack, bool) { return this->loadResource(stack); });
// Registering custom synthetic functions
interpreter->registerFunction(gfxapi::Ids::StartTimer,
[this](Stack* stack, bool) { return this->startTimer(stack); });
interpreter->registerFunction(gfxapi::Ids::StopTimer,
[this](Stack* stack, bool pushReturn) {
return this->stopTimer(stack, pushReturn);
});
interpreter->registerFunction(gfxapi::Ids::FlushPostBuffer, [this](Stack* stack, bool) {
return this->flushPostBuffer(stack);
});
interpreter->registerFunction(gfxapi::Ids::ReplayCreateRenderer, [this](Stack* stack, bool) {
int32_t id = stack->pop<uint32_t>();
if (stack->isValid()) {
GAPID_INFO("replayCreateRenderer(%d)\n", 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\n");
return false;
}
});
interpreter->registerFunction(gfxapi::Ids::ReplayBindRenderer, [this](Stack* stack, bool) {
int32_t id = stack->pop<uint32_t>();
if (stack->isValid()) {
GAPID_INFO("replayBindRenderer(%d)\n", id);
if (mBoundRenderer != nullptr) {
mBoundRenderer->unbind();
mBoundRenderer = nullptr;
}
mBoundRenderer = mRenderers[id];
mBoundRenderer->bind();
return true;
} else {
GAPID_WARNING("Error during calling function replayBindRenderer\n");
return false;
}
});
interpreter->registerFunction(gfxapi::Ids::BackbufferInfo, [this](Stack* stack, bool) {
stack->pop<bool>(); /* preserveBuffersOnSwap - ignored */
bool resetViewportScissor = stack->pop<bool>();
uint32_t stencil_fmt = stack->pop<uint32_t>();
uint32_t depth_fmt = stack->pop<uint32_t>();
uint32_t color_fmt = stack->pop<uint32_t>();
int32_t height = stack->pop<int32_t>();
int32_t width = stack->pop<int32_t>();
if (!stack->isValid()) {
GAPID_WARNING("Error during calling function replayCreateRenderer\n");
return false;
}
uint32_t depthSize = 0;
switch (depth_fmt) {
case static_cast<uint32_t>(gfxapi::GLenum::GL_DEPTH_COMPONENT16):
depthSize = 16;
break;
case static_cast<uint32_t>(gfxapi::GLenum::GL_DEPTH24_STENCIL8):
depthSize = 24;
break;
}
uint32_t stencilSize = 0;
switch (stencil_fmt) {
case static_cast<uint32_t>(gfxapi::GLenum::GL_STENCIL_INDEX8):
case static_cast<uint32_t>(gfxapi::GLenum::GL_DEPTH24_STENCIL8):
stencilSize = 8;
}
if (stack->isValid()) {
GAPID_INFO("backbufferInfo(%d, %d, 0x%x, 0x%x, 0x%x)\n",
width, height, color_fmt, depth_fmt, stencil_fmt,
resetViewportScissor ? "true" : "false");
if (mBoundRenderer == nullptr) {
GAPID_INFO("backbufferInfo called without a bound renderer\n");
return false;
}
mBoundRenderer->setBackbuffer(width, height, depthSize, stencilSize);
if (resetViewportScissor) {
gfxapi::glViewport(0, 0, width, height);
gfxapi::glScissor(0, 0, width, height);
}
return true;
} else {
GAPID_WARNING("Error during calling function replayCreateRenderer\n");
return false;
}
mBoundRenderer->setBackbuffer(width, height, depthSize, stencilSize);
if (resetViewportScissor) {
gfxapi::glViewport(0, 0, width, height);
gfxapi::glScissor(0, 0, width, height);
}
return true;
});
}
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\n");
return false;
}
const auto& resourceData = mReplayRequest->getResourceData(resourceId);
if (!mMemoryManager->isVolatileAddressWithSize(address, resourceData.second)) {
GAPID_WARNING("Invalid volatile address in loadResource %p\n", address);
return false;
}
if (!mResourceProvider->get(resourceData.first, mServer, address, resourceData.second)) {
GAPID_WARNING("Can't fetch resource: %s\n", resourceData.first.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\n");
return false;
}
return mPostBuffer->push(address, count);
}
bool Context::flushPostBuffer(Stack* stack) {
if (!stack->isValid()) {
GAPID_WARNING("Error during flushPostBuffer\n");
return false;
}
return mPostBuffer->flush();
}
bool Context::startTimer(Stack* stack) {
uint8_t index = stack->pop<uint8_t>();
if (stack->isValid()) {
if (index < MAX_TIMERS) {
GAPID_INFO("startTimer(%d)\n", index);
mTimers[index].Start();
return true;
} else {
GAPID_WARNING("StartTimer called with invalid index %d\n", index);
}
} else {
GAPID_WARNING("Error while calling function StartTimer\n");
}
return false;
}
bool Context::stopTimer(Stack* stack, bool pushReturn) {
uint8_t index = stack->pop<uint8_t>();
if (stack->isValid()) {
if (index < MAX_TIMERS) {
GAPID_INFO("stopTimer(%d)\n", index);
uint64_t ns = mTimers[index].Stop();
if (pushReturn) {
stack->push(ns);
}
return true;
} else {
GAPID_WARNING("StopTimer called with invalid index %d\n", index);
}
} else {
GAPID_WARNING("Error while calling function StopTimer\n");
}
return false;
}
} // namespace gapir