blob: ec0359dc0552deaa622cd0fec5a46b131e3752ba [file] [log] [blame]
from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, CUSTOM_CREATE_APIS
from .marshaling import VulkanMarshalingCodegen
from .handlemap import HandleMapCodegen
from .deepcopy import DeepcopyCodegen
from .wrapperdefs import API_PREFIX_MARSHAL
from .wrapperdefs import API_PREFIX_UNMARSHAL
encoder_decl_preamble = """
class VkEncoder {
public:
VkEncoder(IOStream* stream);
~VkEncoder();
"""
encoder_decl_postamble = """
private:
class Impl;
std::unique_ptr<Impl> mImpl;
};
"""
encoder_impl_preamble ="""
using namespace goldfish_vk;
using android::aligned_buf_alloc;
using android::aligned_buf_free;
using android::base::Pool;
class VkEncoder::Impl {
public:
Impl(IOStream* stream) : m_stream(stream) { }
VulkanCountingStream* countingStream() { return &m_countingStream; }
VulkanStream* stream() { return &m_stream; }
Pool* pool() { return &m_pool; }
ResourceTracker* resources() { return ResourceTracker::get(); }
private:
VulkanCountingStream m_countingStream;
VulkanStream m_stream;
Pool m_pool { 8, 4096, 64 };
};
VkEncoder::VkEncoder(IOStream *stream) :
mImpl(new VkEncoder::Impl(stream)) { }
#define VALIDATE_RET(retType, success, validate) \\
retType goldfish_vk_validateResult = validate; \\
if (goldfish_vk_validateResult != success) return goldfish_vk_validateResult; \\
#define VALIDATE_VOID(validate) \\
VkResult goldfish_vk_validateResult = validate; \\
if (goldfish_vk_validateResult != VK_SUCCESS) return; \\
"""
COUNTING_STREAM = "countingStream"
STREAM = "stream"
RESOURCES = "resources"
POOL = "pool"
ENCODER_PREVALIDATED_APIS = [
"vkFlushMappedMemoryRanges",
"vkInvalidateMappedMemoryRanges",
]
SUCCESS_RET_TYPES = {
"VkResult" : "VK_SUCCESS",
# TODO: Put up success results for other return types here.
}
# Common components of encoding a Vulkan API call
def emit_custom_prevalidate(typeInfo, api, cgen):
if api.name in ENCODER_PREVALIDATED_APIS:
if api.getRetTypeExpr() == "void":
cgen.stmt("VALIDATE_VOID(%s)" % \
cgen.makeCallExpr("validate_%s" % api.name,
[p.paramName for p in api.parameters]))
else:
cgen.stmt("VALIDATE_RET(%s, %s, %s)" % \
(api.getRetTypeExpr(), \
SUCCESS_RET_TYPES[api.getRetTypeExpr()],
cgen.makeCallExpr("validate_%s" % api.name, \
[p.paramName for p in api.parameters]))) \
def emit_count_marshal(typeInfo, param, cgen):
res = \
iterateVulkanType(
typeInfo, param,
VulkanMarshalingCodegen( \
cgen, COUNTING_STREAM, param.paramName,
API_PREFIX_MARSHAL, direction="write"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_marshal(typeInfo, param, cgen):
forOutput = param.isHandleType() and ("out" in param.inout)
if forOutput:
cgen.stmt("%s->unsetHandleMapping() /* emit_marshal, is handle, possibly out */" % STREAM)
res = \
iterateVulkanType(
typeInfo, param,
VulkanMarshalingCodegen( \
cgen, STREAM, param.paramName,
API_PREFIX_MARSHAL, direction="write"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
if forOutput:
cgen.stmt("%s->setHandleMapping(resources->unwrapMapping())" % STREAM)
def emit_unmarshal(typeInfo, param, cgen):
iterateVulkanType(
typeInfo, param,
VulkanMarshalingCodegen( \
cgen, STREAM, param.paramName,
API_PREFIX_UNMARSHAL, direction="read"))
def emit_deepcopy(typeInfo, param, cgen):
res = \
iterateVulkanType(typeInfo, param, DeepcopyCodegen(
cgen, [param.paramName, "local_" + param.paramName], "pool", "deepcopy_"))
if not res:
cgen.stmt("(void)%s" % param.paramName)
def emit_handlemap_create(typeInfo, param, cgen):
iterateVulkanType(typeInfo, param, HandleMapCodegen(
cgen, None, "resources->createMapping()", "handlemap_",
lambda vtype: typeInfo.isHandleType(vtype.typeName)
))
def custom_encoder_args(api):
params = ["this"]
if api.getRetVarExpr() is not None:
params.append(api.getRetVarExpr())
return params
def emit_custom_create(typeInfo, api, cgen):
if api.name in CUSTOM_CREATE_APIS:
cgen.funcCall(
None,
"goldfish_" + api.name,
custom_encoder_args(api) + \
[p.paramName for p in api.parameters])
def emit_handlemap_destroy(typeInfo, param, cgen):
iterateVulkanType(typeInfo, param, HandleMapCodegen(
cgen, None, "resources->destroyMapping()", "handlemap_",
lambda vtype: typeInfo.isHandleType(vtype.typeName)
))
class EncodingParameters(object):
def __init__(self, api):
self.localCopied = []
self.toWrite = []
self.toRead = []
self.toCreate = []
self.toDestroy = []
for param in api.parameters:
param.action = None
param.inout = "in"
if param.possiblyOutput():
param.inout += "out"
self.toWrite.append(param)
self.toRead.append(param)
if param.isCreatedBy(api):
self.toCreate.append(param)
param.action = "create"
else:
if param.isDestroyedBy(api):
self.toDestroy.append(param)
param.action = "destroy"
localCopyParam = \
param.getForNonConstAccess().withModifiedName( \
"local_" + param.paramName)
self.localCopied.append((param, localCopyParam))
self.toWrite.append(localCopyParam)
def emit_parameter_encode_preamble_write(typeInfo, api, cgen):
emit_custom_prevalidate(typeInfo, api, cgen);
cgen.stmt("auto %s = mImpl->stream()" % STREAM)
cgen.stmt("auto %s = mImpl->countingStream()" % COUNTING_STREAM)
cgen.stmt("auto %s = mImpl->resources()" % RESOURCES)
cgen.stmt("auto %s = mImpl->pool()" % POOL)
cgen.stmt("%s->setHandleMapping(%s->unwrapMapping())" % (STREAM, RESOURCES))
encodingParams = EncodingParameters(api)
for (_, localCopyParam) in encodingParams.localCopied:
cgen.stmt(cgen.makeRichCTypeDecl(localCopyParam))
def emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen, customUnwrap=None):
encodingParams = EncodingParameters(api)
for (origParam, localCopyParam) in encodingParams.localCopied:
shouldCustomCopy = \
customUnwrap and \
origParam.paramName in customUnwrap and \
"copyOp" in customUnwrap[origParam.paramName]
if shouldCustomCopy:
customUnwrap[origParam.paramName]["copyOp"](cgen, origParam, localCopyParam)
else:
emit_deepcopy(typeInfo, origParam, cgen)
for (origParam, localCopyParam) in encodingParams.localCopied:
shouldCustomMap = \
customUnwrap and \
origParam.paramName in customUnwrap and \
"mapOp" in customUnwrap[origParam.paramName]
if shouldCustomMap:
customUnwrap[origParam.paramName]["mapOp"](cgen, origParam, localCopyParam)
else:
if localCopyParam.typeName == "VkAllocationCallbacks":
cgen.stmt("%s = nullptr" % localCopyParam.paramName)
cgen.stmt("%s->rewind()" % COUNTING_STREAM)
cgen.beginBlock()
# Use counting stream to calculate the packet size.
for p in encodingParams.toWrite:
emit_count_marshal(typeInfo, p, cgen)
cgen.endBlock()
def emit_parameter_encode_write_packet_info(typeInfo, api, cgen):
cgen.stmt("uint32_t packetSize_%s = 4 + 4 + (uint32_t)%s->bytesWritten()" % \
(api.name, COUNTING_STREAM))
cgen.stmt("%s->rewind()" % COUNTING_STREAM)
cgen.stmt("uint32_t opcode_%s = OP_%s" % (api.name, api.name))
cgen.stmt("%s->write(&opcode_%s, sizeof(uint32_t))" % (STREAM, api.name))
cgen.stmt("%s->write(&packetSize_%s, sizeof(uint32_t))" % (STREAM, api.name))
def emit_parameter_encode_do_parameter_write(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
for p in encodingParams.toWrite:
emit_marshal(typeInfo, p, cgen)
def emit_parameter_encode_read(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
for p in encodingParams.toRead:
if p.action == "create":
cgen.stmt(
"%s->setHandleMapping(%s->createMapping())" % \
(STREAM, RESOURCES))
emit_unmarshal(typeInfo, p, cgen)
if p.action == "create":
cgen.stmt(
"%s->unsetHandleMapping()" % STREAM)
def emit_custom_create_destroy(typeInfo, api, cgen):
encodingParams = EncodingParameters(api)
for p in encodingParams.toCreate:
emit_custom_create(typeInfo, api, cgen)
for p in encodingParams.toDestroy:
emit_handlemap_destroy(typeInfo, p, cgen)
def emit_return_unmarshal(typeInfo, api, cgen):
retType = api.getRetTypeExpr()
if retType == "void":
return
retVar = api.getRetVarExpr()
cgen.stmt("%s %s = (%s)0" % (retType, retVar, retType))
cgen.stmt("%s->read(&%s, %s)" % \
(STREAM, retVar, cgen.sizeofExpr(api.retType)))
cgen.stmt("%s->clearPool()" % COUNTING_STREAM)
cgen.stmt("%s->clearPool()" % STREAM)
cgen.stmt("pool->freeAll()")
def emit_return(typeInfo, api, cgen):
if api.getRetTypeExpr() == "void":
return
retVar = api.getRetVarExpr()
cgen.stmt("return %s" % retVar)
def emit_default_encoding(typeInfo, api, cgen):
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_custom_create_destroy(typeInfo, api, cgen)
emit_return(typeInfo, api, cgen)
## Custom encoding definitions##################################################
def emit_only_goldfish_custom(typeInfo, api, cgen):
cgen.vkApiCall( \
api,
customPrefix="goldfish_",
customParameters=custom_encoder_args(api) + \
[p.paramName for p in api.parameters])
emit_return(typeInfo, api, cgen)
def emit_with_custom_unwrap(custom):
def call(typeInfo, api, cgen):
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(
typeInfo, api, cgen, customUnwrap=custom)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_return(typeInfo, api, cgen)
return call
def encode_vkFlushMappedMemoryRanges(typeInfo, api, cgen):
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
def emit_flush_ranges(streamVar):
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = pMemoryRanges[i].memory")
cgen.stmt("auto size = pMemoryRanges[i].size")
cgen.stmt("auto offset = pMemoryRanges[i].offset")
cgen.stmt("auto goldfishMem = as_goldfish_VkDeviceMemory(memory)")
cgen.stmt("uint64_t streamSize = 0")
cgen.stmt("if (!goldfishMem) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("auto hostPtr = goldfishMem->ptr")
cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? goldfishMem->size : size")
cgen.stmt("if (!hostPtr) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("streamSize = actualSize")
cgen.stmt("%s->write(&streamSize, sizeof(uint64_t))" % streamVar)
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("%s->write(targetRange, actualSize)" % streamVar)
cgen.endFor()
emit_flush_ranges(COUNTING_STREAM)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_flush_ranges(STREAM)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
emit_return(typeInfo, api, cgen)
def encode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
emit_parameter_encode_preamble_write(typeInfo, api, cgen)
emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
emit_parameter_encode_read(typeInfo, api, cgen)
emit_return_unmarshal(typeInfo, api, cgen)
def emit_invalidate_ranges(streamVar):
cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
cgen.stmt("auto range = pMemoryRanges[i]")
cgen.stmt("auto memory = pMemoryRanges[i].memory")
cgen.stmt("auto size = pMemoryRanges[i].size")
cgen.stmt("auto offset = pMemoryRanges[i].offset")
cgen.stmt("auto goldfishMem = as_goldfish_VkDeviceMemory(memory)")
cgen.stmt("uint64_t streamSize = 0")
cgen.stmt("if (!goldfishMem) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("auto hostPtr = goldfishMem->ptr")
cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? goldfishMem->size : size")
cgen.stmt("if (!hostPtr) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
cgen.stmt("streamSize = actualSize")
cgen.stmt("%s->read(&streamSize, sizeof(uint64_t))" % streamVar)
cgen.stmt("uint8_t* targetRange = hostPtr + offset")
cgen.stmt("%s->read(targetRange, actualSize)" % streamVar)
cgen.endFor()
emit_invalidate_ranges(STREAM)
emit_return(typeInfo, api, cgen)
def unwrap_VkNativeBufferANDROID():
def mapOp(cgen, orig, local):
cgen.stmt("goldfish_unwrap_VkNativeBufferANDROID(%s, %s)" %
(orig.paramName, local.paramName))
return { "pCreateInfo" : { "mapOp" : mapOp } }
def unwrap_vkAcquireImageANDROID_nativeFenceFd():
def mapOp(cgen, orig, local):
cgen.stmt("goldfish_unwrap_vkAcquireImageANDROID_nativeFenceFd(%s, &%s)" %
(orig.paramName, local.paramName))
return { "nativeFenceFd" : { "mapOp" : mapOp } }
custom_encodes = {
"vkEnumerateInstanceVersion" : emit_only_goldfish_custom,
"vkEnumerateDeviceExtensionProperties" : emit_only_goldfish_custom,
"vkGetPhysicalDeviceProperties2" : emit_only_goldfish_custom,
"vkMapMemory" : emit_only_goldfish_custom,
"vkUnmapMemory" : emit_only_goldfish_custom,
"vkFlushMappedMemoryRanges" : encode_vkFlushMappedMemoryRanges,
"vkInvalidateMappedMemoryRanges" : encode_vkInvalidateMappedMemoryRanges,
"vkCreateImage" : emit_with_custom_unwrap(unwrap_VkNativeBufferANDROID()),
"vkAcquireImageANDROID" : emit_with_custom_unwrap(unwrap_vkAcquireImageANDROID_nativeFenceFd()),
}
class VulkanEncoder(VulkanWrapperGenerator):
def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo)
self.typeInfo = typeInfo
self.cgenHeader = CodeGen()
self.cgenHeader.incrIndent()
self.cgenImpl = CodeGen()
def onBegin(self,):
self.module.appendHeader(encoder_decl_preamble)
self.module.appendImpl(encoder_impl_preamble)
def onGenCmd(self, cmdinfo, name, alias):
VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
api = self.typeInfo.apis[name]
self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(api))
apiImpl = api.withModifiedName("VkEncoder::" + api.name)
self.module.appendHeader(self.cgenHeader.swapCode())
if api.name in custom_encodes.keys():
self.module.appendImpl(self.cgenImpl.makeFuncImpl(
apiImpl, lambda cgen: custom_encodes[api.name](self.typeInfo, api, cgen)))
else:
self.module.appendImpl(self.cgenImpl.makeFuncImpl(apiImpl,
lambda cgen: emit_default_encoding(self.typeInfo, api, cgen)))
def onEnd(self,):
self.module.appendHeader(encoder_decl_postamble)
self.cgenHeader.decrIndent()