//============================================================================== ScriptManager::ScriptManager(HeapAllocator<U8>& alloc) : LuaBinder(alloc) { ANKI_LOGI("Initializing scripting engine..."); // Global functions ANKI_SCRIPT_CALL_WRAP(Anki); // Math ANKI_SCRIPT_CALL_WRAP(Vec2); ANKI_SCRIPT_CALL_WRAP(Vec3); ANKI_SCRIPT_CALL_WRAP(Vec4); ANKI_SCRIPT_CALL_WRAP(Mat3); // Renderer ANKI_SCRIPT_CALL_WRAP(Dbg); ANKI_SCRIPT_CALL_WRAP(MainRenderer); // Scene ANKI_SCRIPT_CALL_WRAP(MoveComponent); ANKI_SCRIPT_CALL_WRAP(SceneNode); ANKI_SCRIPT_CALL_WRAP(ModelNode); ANKI_SCRIPT_CALL_WRAP(InstanceNode); ANKI_SCRIPT_CALL_WRAP(SceneGraph); ANKI_LOGI("Scripting engine initialized"); }
void GpuMemoryManager::init(VkPhysicalDevice pdev, VkDevice dev, GrAllocator<U8> alloc) { ANKI_ASSERT(pdev); ANKI_ASSERT(dev); // Print some info for(const ClassInf& c : CLASSES) { ANKI_LOGI("VK: GPU mem class. Chunk size: %u, slotSize: %u, allocsPerChunk %u", c.m_chunkSize, c.m_slotSize, c.m_chunkSize / c.m_slotSize); } vkGetPhysicalDeviceMemoryProperties(pdev, &m_memoryProperties); m_alloc = alloc; m_ifaces.create(alloc, m_memoryProperties.memoryTypeCount); for(U i = 0; i < m_ifaces.getSize(); ++i) { Interface& iface = m_ifaces[i]; iface.m_alloc = alloc; iface.m_dev = dev; iface.m_memTypeIdx = i; } // One allocator per type per linear/non-linear resources m_callocs.create(alloc, m_memoryProperties.memoryTypeCount * 2); for(U i = 0; i < m_callocs.getSize(); ++i) { m_callocs[i].init(m_alloc, &m_ifaces[i / 2]); } }
Error GrManagerImpl::initDevice(const GrManagerInitInfo& init) { uint32_t count = 0; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, nullptr); ANKI_LOGI("VK: Number of queue families: %u\n", count); DynamicArrayAuto<VkQueueFamilyProperties> queueInfos(getAllocator()); queueInfos.create(count); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, &queueInfos[0]); uint32_t desiredFamilyIdx = MAX_U32; const VkQueueFlags DESITED_QUEUE_FLAGS = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; for(U i = 0; i < count; ++i) { if((queueInfos[i].queueFlags & DESITED_QUEUE_FLAGS) == DESITED_QUEUE_FLAGS) { VkBool32 supportsPresent = false; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent)); if(supportsPresent) { desiredFamilyIdx = i; break; } } } if(desiredFamilyIdx == MAX_U32) { ANKI_LOGE("Couldn't find a queue family with graphics+compute+transfer+present." "The assumption was wrong. The code needs to be reworked"); return ErrorCode::FUNCTION_FAILED; } m_queueIdx = desiredFamilyIdx; F32 priority = 1.0; VkDeviceQueueCreateInfo q = {}; q.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; q.queueFamilyIndex = desiredFamilyIdx; q.queueCount = 1; q.pQueuePriorities = &priority; static Array<const char*, 1> DEV_EXTENSIONS = {{VK_KHR_SWAPCHAIN_EXTENSION_NAME}}; VkDeviceCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; ci.queueCreateInfoCount = 1; ci.pQueueCreateInfos = &q; ci.enabledExtensionCount = DEV_EXTENSIONS.getSize(); ci.ppEnabledExtensionNames = &DEV_EXTENSIONS[0]; ci.pEnabledFeatures = &m_devFeatures; ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device)); return ErrorCode::NONE; }
//============================================================================== Error ScriptManager::create( AllocAlignedCallback allocCb, void* allocCbData, SceneGraph* scene) { ANKI_LOGI("Initializing scripting engine..."); m_scene = scene; m_alloc = ChainAllocator<U8>(allocCb, allocCbData, 1024, 1.0, 0); Error err = m_lua.create(m_alloc, this); if(err) return err; // Wrap stuff lua_State* l = m_lua.getLuaState(); ANKI_SCRIPT_CALL_WRAP(Math); ANKI_SCRIPT_CALL_WRAP(Renderer); ANKI_SCRIPT_CALL_WRAP(Scene); ANKI_LOGI("Scripting engine initialized"); return err; }
static void handleAndroidEvents(android_app* app, int32_t cmd) { Input* input = (Input*)app->userData; ANKI_ASSERT(input != nullptr); switch(cmd) { case APP_CMD_TERM_WINDOW: case APP_CMD_LOST_FOCUS: ANKI_LOGI("New event 0x%x", cmd); input->addEvent(Input::WINDOW_CLOSED_EVENT); break; } }
//============================================================================== void RenderingThread::prepare() { m_manager->getImplementation().pinContextToCurrentThread(true); // Ignore the first error glGetError(); ANKI_LOGI("OpenGL async thread started: OpenGL version %s, GLSL version %s", reinterpret_cast<const char*>(glGetString(GL_VERSION)), reinterpret_cast<const char*>( glGetString(GL_SHADING_LANGUAGE_VERSION))); // Get thread id m_serverThreadId = Thread::getCurrentThreadId(); // Init state m_manager->getImplementation().getState().initRenderThread(); // Init dyn mem m_manager->getImplementation().getDynamicMemoryManager().initRenderThread(); }
Error MainRenderer::create(ThreadPool* threadpool, ResourceManager* resources, GrManager* gr, AllocAlignedCallback allocCb, void* allocCbUserData, const ConfigSet& config, Timestamp* globTimestamp) { ANKI_LOGI("Initializing main renderer"); m_alloc = HeapAllocator<U8>(allocCb, allocCbUserData); m_frameAlloc = StackAllocator<U8>(allocCb, allocCbUserData, 1024 * 1024 * 10, 1.0); // Init default FB m_width = config.getNumber("width"); m_height = config.getNumber("height"); FramebufferInitInfo fbInit; fbInit.m_colorAttachmentCount = 1; fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE; m_defaultFb = gr->newInstance<Framebuffer>(fbInit); // Init renderer and manipulate the width/height ConfigSet config2 = config; m_renderingQuality = config.getNumber("renderingQuality"); UVec2 size(m_renderingQuality * F32(m_width), m_renderingQuality * F32(m_height)); size.x() = getAlignedRoundDown(TILE_SIZE, size.x() / 2) * 2; size.y() = getAlignedRoundDown(TILE_SIZE, size.y() / 2) * 2; config2.set("width", size.x()); config2.set("height", size.y()); m_rDrawToDefaultFb = m_renderingQuality == 1.0; m_r.reset(m_alloc.newInstance<Renderer>()); ANKI_CHECK(m_r->init(threadpool, resources, gr, m_alloc, m_frameAlloc, config2, globTimestamp, m_rDrawToDefaultFb)); // Set the default preprocessor string m_materialShaderSource.sprintf(m_alloc, "#define ANKI_RENDERER_WIDTH %u\n" "#define ANKI_RENDERER_HEIGHT %u\n" "#define TILE_SIZE %u\n", m_r->getWidth(), m_r->getHeight(), TILE_SIZE); // Init other if(!m_rDrawToDefaultFb) { ANKI_CHECK(m_r->getResourceManager().loadResource("shaders/Final.frag.glsl", m_blitFrag)); ColorStateInfo colorState; colorState.m_attachmentCount = 1; colorState.m_attachments[0].m_format.m_components = ComponentFormat::DEFAULT_FRAMEBUFFER; m_r->createDrawQuadPipeline(m_blitFrag->getGrShader(), colorState, m_blitPpline); // Init RC group ResourceGroupInitInfo rcinit; rcinit.m_textures[0].m_texture = m_r->getPps().getRt(); m_rcGroup = m_r->getGrManager().newInstance<ResourceGroup>(rcinit); ANKI_LOGI("The main renderer will have to blit the offscreen renderer's result"); } ANKI_LOGI("Main renderer initialized. Rendering size %ux%u", m_width, m_height); return ErrorCode::NONE; }
MainRenderer::~MainRenderer() { ANKI_LOGI("Destroying main renderer"); m_materialShaderSource.destroy(m_alloc); }
//============================================================================== static ANKI_USE_RESULT Error loadAnkiTexture( const CString& filename, U32 maxTextureSize, ImageLoader::DataCompression& preferredCompression, DArray<ImageLoader::Surface>& surfaces, GenericMemoryPoolAllocator<U8>& alloc, U8& depth, U8& mipLevels, ImageLoader::TextureType& textureType, ImageLoader::ColorFormat& colorFormat) { File file; ANKI_CHECK(file.open(filename, File::OpenFlag::READ | File::OpenFlag::BINARY | File::OpenFlag::LITTLE_ENDIAN)); // // Read and check the header // AnkiTextureHeader header; ANKI_CHECK(file.read(&header, sizeof(AnkiTextureHeader))); if(std::memcmp(&header.m_magic[0], "ANKITEX1", 8) != 0) { ANKI_LOGE("Wrong magic word"); return ErrorCode::USER_DATA; } if(header.m_width == 0 || !isPowerOfTwo(header.m_width) || header.m_width > 4096 || header.m_height == 0 || !isPowerOfTwo(header.m_height) || header.m_height > 4096) { ANKI_LOGE("Incorrect width/height value"); return ErrorCode::USER_DATA; } if(header.m_depth < 1 || header.m_depth > 16) { ANKI_LOGE("Zero or too big depth"); return ErrorCode::USER_DATA; } if(header.m_type < ImageLoader::TextureType::_2D || header.m_type > ImageLoader::TextureType::_2D_ARRAY) { ANKI_LOGE("Incorrect header: texture type"); return ErrorCode::USER_DATA; } if(header.m_colorFormat < ImageLoader::ColorFormat::RGB8 || header.m_colorFormat > ImageLoader::ColorFormat::RGBA8) { ANKI_LOGE("Incorrect header: color format"); return ErrorCode::USER_DATA; } if((header.m_compressionFormats & preferredCompression) == ImageLoader::DataCompression::NONE) { ANKI_LOGI("File does not contain the requested compression"); // Fallback preferredCompression = ImageLoader::DataCompression::RAW; if((header.m_compressionFormats & preferredCompression) == ImageLoader::DataCompression::NONE) { ANKI_LOGI("File does not contain raw compression"); return ErrorCode::USER_DATA; } } if(header.m_normal != 0 && header.m_normal != 1) { ANKI_LOGE("Incorrect header: normal"); return ErrorCode::USER_DATA; } // Check mip levels U size = min(header.m_width, header.m_height); U maxsize = max(header.m_width, header.m_height); mipLevels = 0; U tmpMipLevels = 0; while(size >= 4) // The minimum size is 4x4 { ++tmpMipLevels; if(maxsize <= maxTextureSize) { ++mipLevels; } size /= 2; maxsize /= 2; } if(header.m_mipLevels > tmpMipLevels) { ANKI_LOGE("Incorrect number of mip levels"); return ErrorCode::USER_DATA; } mipLevels = min<U>(mipLevels, header.m_mipLevels); colorFormat = header.m_colorFormat; switch(header.m_type) { case ImageLoader::TextureType::_2D: depth = 1; break; case ImageLoader::TextureType::CUBE: depth = 6; break; case ImageLoader::TextureType::_3D: case ImageLoader::TextureType::_2D_ARRAY: depth = header.m_depth; break; default: ANKI_ASSERT(0); } textureType = header.m_type; // // Move file pointer // if(preferredCompression == ImageLoader::DataCompression::RAW) { // Do nothing } else if(preferredCompression == ImageLoader::DataCompression::S3TC) { if((header.m_compressionFormats & ImageLoader::DataCompression::RAW) != ImageLoader::DataCompression::NONE) { // If raw compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), File::SeekOrigin::CURRENT)); } } else if(preferredCompression == ImageLoader::DataCompression::ETC) { if((header.m_compressionFormats & ImageLoader::DataCompression::RAW) != ImageLoader::DataCompression::NONE) { // If raw compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), File::SeekOrigin::CURRENT)); } if((header.m_compressionFormats & ImageLoader::DataCompression::S3TC) != ImageLoader::DataCompression::NONE) { // If s3tc compression is present then skip it ANKI_CHECK(file.seek( calcSizeOfSegment(header, ImageLoader::DataCompression::S3TC), File::SeekOrigin::CURRENT)); } } // // It's time to read // // Allocate the surfaces surfaces.create(alloc, mipLevels * depth); // Read all surfaces U mipWidth = header.m_width; U mipHeight = header.m_height; U index = 0; for(U mip = 0; mip < header.m_mipLevels; mip++) { for(U d = 0; d < depth; d++) { U dataSize = calcSurfaceSize( mipWidth, mipHeight, preferredCompression, header.m_colorFormat); // Check if this mipmap can be skipped because of size if(max(mipWidth, mipHeight) <= maxTextureSize) { ImageLoader::Surface& surf = surfaces[index++]; surf.m_width = mipWidth; surf.m_height = mipHeight; surf.m_data.create(alloc, dataSize); ANKI_CHECK(file.read(&surf.m_data[0], dataSize)); } else { ANKI_CHECK(file.seek(dataSize, File::SeekOrigin::CURRENT)); } } mipWidth /= 2; mipHeight /= 2; } return ErrorCode::NONE; }
//============================================================================== void NativeWindowImpl::create(NativeWindowInitInfo& init) { Array<EGLint, 256> attribs; U attr = 0; EGLint configsCount; EGLint format; EGLConfig config; ANKI_LOGI("Creating native window"); ANKI_ASSERT(gAndroidApp); android_app& andApp = *gAndroidApp; loopUntilWindowIsReady(andApp); // EGL init // display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(display == EGL_NO_DISPLAY) { throw ANKI_EXCEPTION("Failed to create display"); } int major, minor; if(eglInitialize(display, &major, &minor) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to initialize EGL"); } // // EGL config // attribs[attr++] = EGL_SURFACE_TYPE; attribs[attr++] = EGL_WINDOW_BIT; attribs[attr++] = EGL_RENDERABLE_TYPE; attribs[attr++] = EGL_OPENGL_ES2_BIT; if(init.samplesCount > 1) { attribs[attr++] = EGL_SAMPLES; attribs[attr++] = init.samplesCount; } attribs[attr++] = EGL_RED_SIZE; attribs[attr++] = init.rgbaBits[0]; attribs[attr++] = EGL_GREEN_SIZE; attribs[attr++] = init.rgbaBits[1]; attribs[attr++] = EGL_BLUE_SIZE; attribs[attr++] = init.rgbaBits[2]; attribs[attr++] = EGL_ALPHA_SIZE; attribs[attr++] = init.rgbaBits[3]; attribs[attr++] = EGL_DEPTH_SIZE; attribs[attr++] = init.depthBits; attribs[attr++] = EGL_STENCIL_SIZE; attribs[attr++] = init.stencilBits; attribs[attr++] = EGL_NONE; if(eglChooseConfig(display, &attribs[0], &config, 1, &configsCount) == EGL_FALSE) { throw ANKI_EXCEPTION("Failed to query required EGL configs"); } if(configsCount == 0) { throw ANKI_EXCEPTION("No matching EGL configs found"); } eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); ANKI_ASSERT(andApp.window); ANativeWindow_setBuffersGeometry(andApp.window, 0, 0, format); // Surface // surface = eglCreateWindowSurface(display, config, andApp.window, NULL); if(surface == EGL_NO_SURFACE) { throw ANKI_EXCEPTION("Cannot create surface"); } // Context // EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttribs); if(context == EGL_NO_CONTEXT) { throw ANKI_EXCEPTION("Cannot create context"); } if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { throw ANKI_EXCEPTION("Cannot make the context current"); } // Query width and height // EGLint w, h; eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_HEIGHT, &h); init.width = w; init.height = h; }
//============================================================================== ScriptManager::~ScriptManager() { ANKI_LOGI("Destroying scripting engine..."); }
//============================================================================== Error NativeWindow::create(Initializer& init, HeapAllocator<U8>& alloc) { m_alloc = alloc; m_impl = m_alloc.newInstance<NativeWindowImpl>(); if(SDL_Init(INIT_SUBSYSTEMS) != 0) { ANKI_LOGE("SDL_Init() failed"); return ErrorCode::FUNCTION_FAILED; } // // Set GL attributes // ANKI_LOGI("Creating SDL window (OpenGL context to be requested %u.%u)...", init.m_majorVersion, init.m_minorVersion); if(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, init.m_rgbaBits[0]) != 0 || SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, init.m_rgbaBits[1]) != 0 || SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, init.m_rgbaBits[2]) != 0 || SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, init.m_rgbaBits[3]) != 0 || SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, init.m_depthBits) != 0 || SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, init.m_doubleBuffer) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, init.m_majorVersion) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, init.m_minorVersion) != 0 || SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) { ANKI_LOGE("SDL_GL_SetAttribute() failed"); return ErrorCode::FUNCTION_FAILED; } if(init.m_debugContext) { if(SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG) != 0) { ANKI_LOGE("SDL_GL_SetAttribute() failed"); return ErrorCode::FUNCTION_FAILED; } } // // Create window // U32 flags = SDL_WINDOW_OPENGL; if(init.m_fullscreenDesktopRez) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } m_impl->m_window = SDL_CreateWindow( init.m_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, init.m_width, init.m_height, flags); if(m_impl->m_window == nullptr) { ANKI_LOGE("SDL_CreateWindow() failed"); return ErrorCode::FUNCTION_FAILED; } // Set the size after loading a fullscreen window if(init.m_fullscreenDesktopRez) { int w, h; SDL_GetWindowSize(m_impl->m_window, &w, &h); m_width = w; m_height = h; } else { m_width = init.m_width; m_height = init.m_height; } // // Create context // m_impl->m_context = SDL_GL_CreateContext(m_impl->m_window); if(m_impl->m_context == nullptr) { ANKI_LOGE("SDL_GL_CreateContext() failed"); return ErrorCode::FUNCTION_FAILED; } // // GLEW // glewExperimental = GL_TRUE; if(glewInit() != GLEW_OK) { ANKI_LOGE("GLEW initialization failed"); return ErrorCode::FUNCTION_FAILED; } glGetError(); ANKI_LOGI("SDL window created"); return ErrorCode::NONE; }
Error GrManagerImpl::initSwapchain(const GrManagerInitInfo& init) { VkSurfaceCapabilitiesKHR surfaceProperties; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &surfaceProperties)); if(surfaceProperties.currentExtent.width == MAX_U32 || surfaceProperties.currentExtent.height == MAX_U32) { ANKI_LOGE("Wrong surface size"); return ErrorCode::FUNCTION_FAILED; } m_surfaceWidth = surfaceProperties.currentExtent.width; m_surfaceHeight = surfaceProperties.currentExtent.height; uint32_t formatCount; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr)); DynamicArrayAuto<VkSurfaceFormatKHR> formats(getAllocator()); formats.create(formatCount); ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, &formats[0])); VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR; while(formatCount--) { if(formats[formatCount].format == VK_FORMAT_B8G8R8A8_UNORM) { m_surfaceFormat = formats[formatCount].format; colorspace = formats[formatCount].colorSpace; break; } } if(m_surfaceFormat == VK_FORMAT_UNDEFINED) { ANKI_LOGE("Surface format not found"); return ErrorCode::FUNCTION_FAILED; } // Chose present mode uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, nullptr); presentModeCount = min(presentModeCount, 4u); Array<VkPresentModeKHR, 4> presentModes; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, &presentModes[0]); VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; if(init.m_config->getNumber("vsync")) { presentMode = VK_PRESENT_MODE_FIFO_KHR; } else { for(U i = 0; i < presentModeCount; ++i) { if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } else if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } } } if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { ANKI_LOGE("VK: Couldn't find a present mode"); return ErrorCode::FUNCTION_FAILED; } // Create swapchain VkSwapchainCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; ci.surface = m_surface; ci.minImageCount = MAX_FRAMES_IN_FLIGHT; ci.imageFormat = m_surfaceFormat; ci.imageColorSpace = colorspace; ci.imageExtent = surfaceProperties.currentExtent; ci.imageArrayLayers = 1; ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; ci.queueFamilyIndexCount = 1; ci.pQueueFamilyIndices = &m_queueIdx; ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; ci.presentMode = presentMode; ci.clipped = false; ci.oldSwapchain = VK_NULL_HANDLE; ANKI_VK_CHECK(vkCreateSwapchainKHR(m_device, &ci, nullptr, &m_swapchain)); // Get images uint32_t count = 0; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &count, nullptr)); if(count != MAX_FRAMES_IN_FLIGHT) { ANKI_LOGE("Requested a swapchain with %u images but got one with %u", MAX_FRAMES_IN_FLIGHT, count); return ErrorCode::FUNCTION_FAILED; } ANKI_LOGI("VK: Created a swapchain. Image count: %u, present mode: %u", count, presentMode); Array<VkImage, MAX_FRAMES_IN_FLIGHT> images; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &count, &images[0])); for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { m_backbuffers[i].m_image = images[i]; ANKI_ASSERT(images[i]); } // Create img views for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { VkImageViewCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; ci.flags = 0; ci.image = m_backbuffers[i].m_image; ci.viewType = VK_IMAGE_VIEW_TYPE_2D; ci.format = m_surfaceFormat; ci.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ci.subresourceRange.baseMipLevel = 0; ci.subresourceRange.levelCount = 1; ci.subresourceRange.baseArrayLayer = 0; ci.subresourceRange.layerCount = 1; ANKI_VK_CHECK(vkCreateImageView(m_device, &ci, nullptr, &m_backbuffers[i].m_imageView)); } return ErrorCode::NONE; }
Error GrManagerImpl::initInstance(const GrManagerInitInfo& init) { // Create the instance // static Array<const char*, 8> LAYERS = {{"VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_LUNARG_image", "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_GOOGLE_unique_objects", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_standard_validation"}}; static Array<const char*, 2> EXTENSIONS = {{VK_KHR_SURFACE_EXTENSION_NAME, #if ANKI_OS == ANKI_OS_LINUX VK_KHR_XCB_SURFACE_EXTENSION_NAME #elif ANKI_OS == ANKI_OS_WINDOWS VK_KHR_WIN32_SURFACE_EXTENSION_NAME #else #error TODO #endif }}; VkApplicationInfo app = {}; app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app.pApplicationName = "unamed"; app.applicationVersion = 1; app.pEngineName = "AnKi 3D Engine"; app.engineVersion = (ANKI_VERSION_MAJOR << 1) | ANKI_VERSION_MINOR; app.apiVersion = VK_MAKE_VERSION(1, 0, 3); VkInstanceCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; ci.pApplicationInfo = &app; if(init.m_config->getNumber("debugContext")) { ANKI_LOGI("VK: Will enable debug layers"); ci.enabledLayerCount = LAYERS.getSize(); ci.ppEnabledLayerNames = &LAYERS[0]; } ci.enabledExtensionCount = EXTENSIONS.getSize(); ci.ppEnabledExtensionNames = &EXTENSIONS[0]; #if ANKI_GR_MANAGER_DEBUG_MEMMORY VkAllocationCallbacks allocCbs = {}; VkAllocationCallbacks* pallocCbs = &allocCbs; allocCbs.pUserData = this; allocCbs.pfnAllocation = allocateCallback; allocCbs.pfnReallocation = reallocateCallback; allocCbs.pfnFree = freeCallback; #else VkAllocationCallbacks* pallocCbs = nullptr; #endif ANKI_VK_CHECK(vkCreateInstance(&ci, pallocCbs, &m_instance)); // Create the physical device // uint32_t count = 0; ANKI_VK_CHECK(vkEnumeratePhysicalDevices(m_instance, &count, nullptr)); ANKI_LOGI("VK: Number of physical devices: %u", count); if(count < 1) { ANKI_LOGE("Wrong number of physical devices"); return ErrorCode::FUNCTION_FAILED; } count = 1; ANKI_VK_CHECK(vkEnumeratePhysicalDevices(m_instance, &count, &m_physicalDevice)); vkGetPhysicalDeviceProperties(m_physicalDevice, &m_devProps); // Find vendor switch(m_devProps.vendorID) { case 0x13B5: m_vendor = GpuVendor::ARM; break; case 0x10DE: m_vendor = GpuVendor::NVIDIA; break; case 0x1002: case 0x1022: m_vendor = GpuVendor::AMD; break; } ANKI_LOGI("GPU vendor is %s", &GPU_VENDOR_STR[m_vendor][0]); vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_devFeatures); return ErrorCode::NONE; }
Error GrManagerImpl::initInternal(const GrManagerInitInfo& init) { ANKI_LOGI("Initializing Vulkan backend"); ANKI_CHECK(initInstance(init)); ANKI_CHECK(initSurface(init)); ANKI_CHECK(initDevice(init)); vkGetDeviceQueue(m_device, m_queueIdx, 0, &m_queue); ANKI_CHECK(initSwapchain(init)); { VkPipelineCacheCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; vkCreatePipelineCache(m_device, &ci, nullptr, &m_pplineCache); } ANKI_CHECK(initMemory(*init.m_config)); ANKI_CHECK(m_dsetAlloc.init(getAllocator(), m_device)); m_pplineLayFactory.init(getAllocator(), m_device, &m_dsetAlloc.getDescriptorSetLayoutFactory()); for(PerFrame& f : m_perFrame) { resetFrame(f); } glslang::InitializeProcess(); m_fences.init(getAllocator(), m_device); m_semaphores.init(getAllocator(), m_device); m_queryAlloc.init(getAllocator(), m_device); m_samplerCache = getAllocator().newInstance<GrObjectCache>(m_manager); // Set m_r8g8b8ImagesSupported { VkImageFormatProperties props = {}; VkResult res = vkGetPhysicalDeviceImageFormatProperties(m_physicalDevice, VK_FORMAT_R8G8B8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &props); if(res == VK_ERROR_FORMAT_NOT_SUPPORTED) { ANKI_LOGI("R8G8B8 Images are not supported. Will workaround this"); m_r8g8b8ImagesSupported = false; } else { ANKI_ASSERT(res == VK_SUCCESS); ANKI_LOGI("R8G8B8 Images are supported"); m_r8g8b8ImagesSupported = true; } } // Set m_s8ImagesSupported { VkImageFormatProperties props = {}; VkResult res = vkGetPhysicalDeviceImageFormatProperties(m_physicalDevice, VK_FORMAT_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &props); if(res == VK_ERROR_FORMAT_NOT_SUPPORTED) { ANKI_LOGI("S8 Images are not supported. Will workaround this"); m_s8ImagesSupported = false; } else { ANKI_ASSERT(res == VK_SUCCESS); ANKI_LOGI("S8 Images are supported"); m_s8ImagesSupported = true; } } // Set m_d24S8ImagesSupported { VkImageFormatProperties props = {}; VkResult res = vkGetPhysicalDeviceImageFormatProperties(m_physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &props); if(res == VK_ERROR_FORMAT_NOT_SUPPORTED) { ANKI_LOGI("D24S8 Images are not supported. Will workaround this"); m_d24S8ImagesSupported = false; } else { ANKI_ASSERT(res == VK_SUCCESS); ANKI_LOGI("D24S8 Images are supported"); m_d24S8ImagesSupported = true; } } return ErrorCode::NONE; }