Exemple #1
0
// ***********************************************************************
// ***********************************************************************
// project5 command
//
//
int P5_project5(int argc, char* argv[])		// project 5
{
	int i;
	char* new_argv[4];						// child arguments
	char arg1[16];
	char arg2[16];
	char arg3[16];

	static char* groupReportArgv[] = {"groupReport", "4"};

	// check if just changing scheduler mode
	if (argc > 1)
	{
		scheduler_mode = atoi(argv[1]);
		printf("\nScheduler Mode = %d (%s)", scheduler_mode, scheduler_mode ? "FSS" : "RR");
		return 0;
	}

	printf("\nStarting Project 5");

	for (i = 0; i < NUM_PARENTS; ++i)
	{
		num_siblings[i] = (rand() % 25) + 1;
		printf("\nGroup[%d] = %d", i, num_siblings[i]);
	}

	childALive = createSemaphore("childALive", BINARY, 0);
	parentDead = createSemaphore("parentDead", BINARY, 0);

	// create parents
	for (i = 0; i < NUM_PARENTS; i++)
	{
		group_count[i] = 0;					// zero group counter

		sprintf(arg1, "parent%d", i + 1);
		sprintf(arg2, "%d", i + 1);
//		sprintf(arg3, "%d", 1 + 4 * i);
		sprintf(arg3, "%d", num_siblings[i]);
		new_argv[0] = arg1;
		new_argv[1] = arg2;
		new_argv[2] = arg3;

		printf("\nCreate %s with %d child%s", arg1, atoi(arg3), (atoi(arg3) == 1 ? "" : "ren"));
		createTask(new_argv[0]				// task name
				 , parentTask,				// parent task
				   MED_PRIORITY,			// priority
				   3,						// argc
				   new_argv);				// argv
		SEM_WAIT(parentDead);				// wait for parent to die
	}

	// create reporting task
	createTask("Group Report"	,			// task name
				groupReportTask,			// task
				MED_PRIORITY,				// task priority
				2,							// task argc
				groupReportArgv);			// task argument pointers
	return 0;
} // end P5_project5
/// <summary>
/// Initialize all the semphores to be used
/// </summary>
void initializeSemaphores()
{
    printf("Inicializando Semaforos... \n");

    createSemaphore(CHAIRS_SEM);
    createSemaphore(BARBERS_SEM);
    createSemaphore(CASHIER_SEM);
    createSemaphore(S_CLIENTS_COUNTER_SEM);

    // Write file header
    Semaphore *fileSem = createSemaphore(FILE_SEM);
    sem_wait(fileSem->mutex);
    writeFile(FILE_HEADER);
    sem_post(fileSem->mutex);

    printf("Semaforos creados exitosamente! \n");
}
Exemple #3
0
// **********************************************************************
// **********************************************************************
// create task
int createTask(char* name,						// task name
					int (*task)(int, char**),	// task address
					int priority,				// task priority
					int argc,					// task argument count
					char* argv[])				// task argument pointers
{
	int tid;

	// find an open tcb entry slot
	for (tid = 0; tid < MAX_TASKS; tid++)
	{
		if (tcb[tid].name == 0)
		{
			char buf[8];

			// create task semaphore
			if (taskSems[tid]) deleteSemaphore(&taskSems[tid]);
			sprintf(buf, "task%d", tid);
			taskSems[tid] = createSemaphore(buf, 0, 0);
			taskSems[tid]->taskNum = 0;	// assign to shell

			// copy task name
			tcb[tid].name = (char*)malloc(strlen(name)+1);
			strcpy(tcb[tid].name, name);

			// set task address and other parameters
			tcb[tid].task = task;			// task address
			tcb[tid].state = S_NEW;			// NEW task state
			tcb[tid].priority = priority;	// task priority
			tcb[tid].parent = curTask;		// parent
			tcb[tid].argc = argc;			// argument count

			// ?? malloc new argv parameters
			tcb[tid].argv = malloc(argc*sizeof(char *));
			int i;
			for (i = 0; i < argc; i++)
			tcb[tid].argv[i] = argv[i];			// argument pointers

			tcb[tid].event = 0;				// suspend semaphore
			tcb[tid].RPT = 0;					// root page table (project 5)
			tcb[tid].cdir = CDIR;			// inherit parent cDir (project 6)

			// define task signals
			createTaskSigHandlers(tid);

			// Each task must have its own stack and stack pointer.
			tcb[tid].stack = malloc(STACK_SIZE * sizeof(int));

			// ?? may require inserting task into "ready" queue

			if (tid) swapTask();				// do context switch (if not cli)
			return tid;							// return tcb index (curTask)
		}
	}
	// tcb full!
	return -1;
} // end createTask
void learnProcessSemaphores()
{
    int sem_id = createSemaphore();    
    
    /*semaphorePost(sem_id);*/
    semaphoreGetCount(sem_id);
    /*sleep(1000);*/
    semaphoreWait(sem_id);
    semaphoreGetCount(sem_id);
}
vk::Move<vk::VkSemaphore> createAndImportSemaphore (const vk::DeviceInterface&						vkd,
													const vk::VkDevice								device,
													vk::VkExternalSemaphoreHandleTypeFlagBitsKHR	externalType,
													NativeHandle&									handle,
													vk::VkSemaphoreImportFlagsKHR					flags)
{
	vk::Move<vk::VkSemaphore>	semaphore	(createSemaphore(vkd, device));

	importSemaphore(vkd, device, *semaphore, externalType, handle, flags);

	return semaphore;
}
Exemple #6
0
int main()
{
    int key1=ftok(".",1);
    int key2=ftok(".",2);
    int key3=ftok(".",3);
    printf("%d %d %d",key1,key2,key3);
    int semid =createSemaphore(key1,2);//S1 S2
    int shmid1=createSharedMemory(key2,10);//x
    printf("shmid1 %d from main\n",shmid1);
    char *X   =(char *)attachSharedMemory(shmid1); 
//    int shmid2=createSharedMemory(key3,10);//y
  //  printf("shmid2 %d from main\n",shmid2);
    char *Y  ; //=//(char *)attachSharedMemory(shmid2);
    int *values=(int *)malloc(sizeof(int *)*2);
    *values=0;*(values+1)=0;
    initSemaphore(semid,values);
/*    V(semid,0);
    printf("hi");
    P(semid,0);
*/   
    int x=0,y=0,i;
    while(1)
	{
	 // write(x)
 	  i=0;
	  printf("P1 X=%d Y=%d\n",x,y);
          while(x>0)
		{
		  *X=x%10-'0';x/=10;X++;i++;
		}
	  printf("*\n");
	  *X='\0';
	  printf("*\n");
	  X-=i;//X Points to start of shared memory  	
	 //V(1)
          V(semid,0);
	 //P(2)
	  P(semid,1);
	 //Read Y
          i=0;
	  while(*Y!='\0')
		{
		   y=y*10+(*Y+'0');Y++;i++;
		}
	  Y-=i; 
	 //X=Y+1;
	  x=y+1;	
	   printf("P1 X=%d Y=%d\n",x,y);
	}
} 
Exemple #7
0
int signalTask(int argc, char* argv[])
{
	int count = 0;					// task variable

	// create a semaphore
	Semaphore** mySem = (!strcmp(argv[1], "s1Sem")) ? &s1Sem : &s2Sem;
	*mySem = createSemaphore(argv[1], 0, 0);

	// loop waiting for semaphore to be signaled
	while(count < COUNT_MAX)
	{
		SEM_WAIT(*mySem);			// wait for signal
		printf("\n%s  Task[%d], count=%d", tcb[curTask].name, curTask, ++count);
	}
	return 0;						// terminate task
} // end signalTask
Exemple #8
0
/**
 * signalTask
 */
int signalTask(int argc, char* argv[])
{
	int count = 0;					/* task variable */
	TCB* tcb = getTCB();
	int curTask = gettid();

	// create a semaphore
	int* mySem = (!strcmp(argv[1], "s1Sem")) ? &s1Sem : &s2Sem;
	*mySem = createSemaphore(argv[1], 0, 1);

	// loop waiting for semaphore to be signaled
	while(count < COUNT_MAX)
	{
		semWait(*mySem);
		printf("%s  Task[%d], count=%d\n", tcb[curTask].name, curTask, ++count);
	}

	return 0;
}
Exemple #9
0
// **********************************************************************
// **********************************************************************
// OS startup
//
// 1. Init OS
// 2. Define reset longjmp vector
// 3. Define global system semaphores
// 4. Create CLI task
// 5. Enter scheduling/idle loop
//
int main(int argc, char* argv[])
{
	// save context for restart (a system reset would return here...)
	int resetCode = setjmp(reset_context);
	superMode = TRUE;						// supervisor mode

	switch (resetCode)
	{
		case POWER_DOWN_QUIT:				// quit
			powerDown(0);
			printf("\nGoodbye!!");
			return 0;

		case POWER_DOWN_RESTART:			// restart
			powerDown(resetCode);
			printf("\nRestarting system...\n");

		case POWER_UP:						// startup
			break;

		default:
			printf("\nShutting down due to error %d", resetCode);
			powerDown(resetCode);
			return resetCode;
	}

	// output header message
	printf("%s", STARTUP_MSG);

	// initalize OS
	if ( resetCode = initOS()) return resetCode;

	// create global/system semaphores here
	//?? vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

	charReady = createSemaphore("charReady", BINARY, 0);
	inBufferReady = createSemaphore("inBufferReady", BINARY, 0);
	keyboard = createSemaphore("keyboard", BINARY, 1);
	tics1sec = createSemaphore("tics1sec", BINARY, 0);
	tics10thsec = createSemaphore("tics10thsec", BINARY, 0);

	tics10secs = createSemaphore("tics10secs", COUNTING, 0);

	//?? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	// schedule CLI task
	createTask("myShell",			// task name
					P1_shellTask,	// task
					MED_PRIORITY,	// task priority
					argc,			// task arg count
					argv);			// task argument pointers

	// HERE WE GO................

	// Scheduling loop
	// 1. Check for asynchronous events (character inputs, timers, etc.)
	// 2. Choose a ready task to schedule
	// 3. Dispatch task
	// 4. Loop (forever!)

	while(1)									// scheduling loop
	{
		// check for character / timer interrupts
		pollInterrupts();

		// schedule highest priority ready task
		if ((curTask = scheduler()) < 0) continue;

		// dispatch curTask, quit OS if negative return
		if (dispatcher() < 0) break;
	}											// end of scheduling loop

	// exit os
	longjmp(reset_context, POWER_DOWN_QUIT);
	return 0;
} // end main
Exemple #10
0
void createSemMethod(char buffer1[]){

	theTickets = createSemaphore("theTickets", COUNTING, MAX_TICKETS); SWAP;
	passengerRide = createSemaphore("passengerRide", BINARY, 0);
	sellDriverTick = createSemaphore("sellDriverTick", BINARY, 0);
	helloDriverWakeUp = createSemaphore("helloDriverWakeUp", BINARY, 0);
	passengerJumpIntoRide = createSemaphore("passengerJumpIntoRide", BINARY, 0);
	ready2GoDriver = createSemaphore("ready2GoDriver", BINARY, 0);
	driverCar = createSemaphore("driverCar", BINARY, 0);
	noDriverYet = createSemaphore("noDriverYet", BINARY, 0);
	parkEntry = createSemaphore("parkEntry ", COUNTING, 20);
	ticketSold = createSemaphore("ticketSold", BINARY, 0);
	buyTicketMutex = createSemaphore("buyTicketMutex", BINARY, 1);
	rideFinished = createSemaphore("rideFinished", BINARY, 0);
	dinosaur = createSemaphore("dinosaur", BINARY, 1);
	visitMuseum = createSemaphore("visitMuseum", COUNTING, MAX_IN_MUSEUM);
	visitGiftShop = createSemaphore("visitGiftShop", COUNTING, MAX_IN_GIFTSHOP);
	buyGiftMutex = createSemaphore("buyGiftMutex", BINARY, 1);
	driverSellGift = createSemaphore("driverSellGift", BINARY, 0);
	giftSold = createSemaphore("gift sold by driver", BINARY, 0);
	finishingUp = createSemaphore("finishing up", BINARY, 0);
	int i = 0;
	while(i < NUM_DRIVERS){
		sprintf(buffer1, "driver done driving %d", i);
		driverFinished[i] = createSemaphore(buffer1, BINARY, 0);
		i++;
	}
}
void createSwapChainAndImages(VulkanContext& context, VulkanSurfaceContext& surfaceContext) {
    // Pick an image count and format.  According to section 30.5 of VK 1.1, maxImageCount of zero
    // apparently means "that there is no limit on the number of images, though there may be limits
    // related to the total amount of memory used by presentable images."
    uint32_t desiredImageCount = 2;
    const uint32_t maxImageCount = surfaceContext.surfaceCapabilities.maxImageCount;
    if (desiredImageCount < surfaceContext.surfaceCapabilities.minImageCount ||
            (maxImageCount != 0 && desiredImageCount > maxImageCount)) {
        utils::slog.e << "Swap chain does not support " << desiredImageCount << " images.\n";
        desiredImageCount = surfaceContext.surfaceCapabilities.minImageCount;
    }
    surfaceContext.surfaceFormat = surfaceContext.surfaceFormats[0];
    for (const VkSurfaceFormatKHR& format : surfaceContext.surfaceFormats) {
        if (format.format == VK_FORMAT_R8G8B8A8_UNORM) {
            surfaceContext.surfaceFormat = format;
            break;
        }
    }
    const auto compositionCaps = surfaceContext.surfaceCapabilities.supportedCompositeAlpha;
    const auto compositeAlpha = (compositionCaps & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
            VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;

    // Create the low-level swap chain.
    const auto size = surfaceContext.surfaceCapabilities.currentExtent;
    VkSwapchainCreateInfoKHR createInfo {
        .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
        .surface = surfaceContext.surface,
        .minImageCount = desiredImageCount,
        .imageFormat = surfaceContext.surfaceFormat.format,
        .imageColorSpace = surfaceContext.surfaceFormat.colorSpace,
        .imageExtent = size,
        .imageArrayLayers = 1,
        .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
        .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
        .compositeAlpha = compositeAlpha,
        .presentMode = VK_PRESENT_MODE_FIFO_KHR,
        .clipped = VK_TRUE
    };
    VkSwapchainKHR swapchain;
    VkResult result = vkCreateSwapchainKHR(context.device, &createInfo, VKALLOC, &swapchain);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkGetPhysicalDeviceSurfaceFormatsKHR error.");
    surfaceContext.swapchain = swapchain;

    // Extract the VkImage handles from the swap chain.
    uint32_t imageCount;
    result = vkGetSwapchainImagesKHR(context.device, swapchain, &imageCount, nullptr);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkGetSwapchainImagesKHR count error.");
    surfaceContext.swapContexts.resize(imageCount);
    std::vector<VkImage> images(imageCount);
    result = vkGetSwapchainImagesKHR(context.device, swapchain, &imageCount,
            images.data());
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkGetSwapchainImagesKHR error.");
    for (size_t i = 0; i < images.size(); ++i) {
        surfaceContext.swapContexts[i].attachment = {
            .image = images[i],
            .format = surfaceContext.surfaceFormat.format
        };
    }
    utils::slog.i
            << "vkCreateSwapchain"
            << ": " << size.width << "x" << size.height
            << ", " << surfaceContext.surfaceFormat.format
            << ", " << surfaceContext.surfaceFormat.colorSpace
            << ", " << imageCount
            << utils::io::endl;

    // Create image views.
    VkImageViewCreateInfo ivCreateInfo = {};
    ivCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    ivCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    ivCreateInfo.format = surfaceContext.surfaceFormat.format;
    ivCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    ivCreateInfo.subresourceRange.levelCount = 1;
    ivCreateInfo.subresourceRange.layerCount = 1;
    for (size_t i = 0; i < images.size(); ++i) {
        ivCreateInfo.image = images[i];
        result = vkCreateImageView(context.device, &ivCreateInfo, VKALLOC,
                &surfaceContext.swapContexts[i].attachment.view);
        ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkCreateImageView error.");
    }

    createSemaphore(context.device, &surfaceContext.imageAvailable);
    createSemaphore(context.device, &surfaceContext.renderingFinished);

    surfaceContext.depth = {};
}

void createDepthBuffer(VulkanContext& context, VulkanSurfaceContext& surfaceContext,
        VkFormat depthFormat) {
    assert(context.cmdbuffer);

    // Create an appropriately-sized device-only VkImage.
    const auto size = surfaceContext.surfaceCapabilities.currentExtent;
    VkImage depthImage;
    VkImageCreateInfo imageInfo {
        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
        .imageType = VK_IMAGE_TYPE_2D,
        .extent = { size.width, size.height, 1 },
        .format = depthFormat,
        .mipLevels = 1,
        .arrayLayers = 1,
        .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
        .samples = VK_SAMPLE_COUNT_1_BIT,
    };
    VkResult error = vkCreateImage(context.device, &imageInfo, VKALLOC, &depthImage);
    ASSERT_POSTCONDITION(!error, "Unable to create depth image.");

    // Allocate memory for the VkImage and bind it.
    VkMemoryRequirements memReqs;
    vkGetImageMemoryRequirements(context.device, depthImage, &memReqs);
    VkMemoryAllocateInfo allocInfo {
        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
        .allocationSize = memReqs.size,
        .memoryTypeIndex = selectMemoryType(context, memReqs.memoryTypeBits,
                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
    };
    error = vkAllocateMemory(context.device, &allocInfo, nullptr,
            &surfaceContext.depth.memory);
    ASSERT_POSTCONDITION(!error, "Unable to allocate depth memory.");
    error = vkBindImageMemory(context.device, depthImage, surfaceContext.depth.memory, 0);
    ASSERT_POSTCONDITION(!error, "Unable to bind depth memory.");

    // Create a VkImageView so that we can attach depth to the framebuffer.
    VkImageView depthView;
    VkImageViewCreateInfo viewInfo {
        .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
        .image = depthImage,
        .viewType = VK_IMAGE_VIEW_TYPE_2D,
        .format = depthFormat,
        .subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
        .subresourceRange.levelCount = 1,
        .subresourceRange.layerCount = 1,
    };
    error = vkCreateImageView(context.device, &viewInfo, VKALLOC, &depthView);
    ASSERT_POSTCONDITION(!error, "Unable to create depth view.");

    // Transition the depth image into an optimal layout.
    VkImageMemoryBarrier barrier {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .image = depthImage,
        .subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
        .subresourceRange.levelCount = 1,
        .subresourceRange.layerCount = 1,
        .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
    };
    vkCmdPipelineBarrier(context.cmdbuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);

    // Go ahead and set the depth attachment fields, which serves as a signal to VulkanDriver that
    // it is now ready.
    surfaceContext.depth.view = depthView;
    surfaceContext.depth.image = depthImage;
    surfaceContext.depth.format = depthFormat;
}

void transitionDepthBuffer(VulkanContext& context, VulkanSurfaceContext& sc, VkFormat depthFormat) {
    // Begin a new command buffer solely for the purpose of transitioning the image layout.
    SwapContext& swap = getSwapContext(context);
    VkResult result = vkWaitForFences(context.device, 1, &swap.fence, VK_FALSE, UINT64_MAX);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkWaitForFences error.");
    result = vkResetFences(context.device, 1, &swap.fence);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkResetFences error.");
    VkCommandBuffer cmdbuffer = swap.cmdbuffer;
    result = vkResetCommandBuffer(cmdbuffer, 0);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkResetCommandBuffer error.");
    VkCommandBufferBeginInfo beginInfo = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
    };
    result = vkBeginCommandBuffer(cmdbuffer, &beginInfo);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkBeginCommandBuffer error.");
    context.cmdbuffer = cmdbuffer;

    // Create the depth buffer and issue a pipeline barrier command.
    createDepthBuffer(context, sc, depthFormat);

    // Flush the command buffer.
    result = vkEndCommandBuffer(context.cmdbuffer);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkEndCommandBuffer error.");
    context.cmdbuffer = nullptr;
    VkSubmitInfo submitInfo {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .commandBufferCount = 1,
        .pCommandBuffers = &swap.cmdbuffer,
    };
    result = vkQueueSubmit(context.graphicsQueue, 1, &submitInfo, swap.fence);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkQueueSubmit error.");
    swap.submitted = false;
}

void createCommandBuffersAndFences(VulkanContext& context, VulkanSurfaceContext& surfaceContext) {
    // Allocate command buffers.
    VkCommandBufferAllocateInfo allocateInfo = {};
    allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    allocateInfo.commandPool = context.commandPool;
    allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    allocateInfo.commandBufferCount = (uint32_t) surfaceContext.swapContexts.size();
    std::vector<VkCommandBuffer> cmdbufs(allocateInfo.commandBufferCount);
    VkResult result = vkAllocateCommandBuffers(context.device, &allocateInfo, cmdbufs.data());
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkAllocateCommandBuffers error.");
    for (uint32_t i = 0; i < allocateInfo.commandBufferCount; ++i) {
        surfaceContext.swapContexts[i].cmdbuffer = cmdbufs[i];
    }

    // Create fences.
    VkFenceCreateInfo fenceCreateInfo = {};
    fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
    for (uint32_t i = 0; i < allocateInfo.commandBufferCount; i++) {
        result = vkCreateFence(context.device, &fenceCreateInfo, VKALLOC,
                &surfaceContext.swapContexts[i].fence);
        ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkCreateFence error.");
    }
}

void destroySurfaceContext(VulkanContext& context, VulkanSurfaceContext& surfaceContext) {
    for (SwapContext& swapContext : surfaceContext.swapContexts) {
        vkFreeCommandBuffers(context.device, context.commandPool, 1, &swapContext.cmdbuffer);
        vkDestroyFence(context.device, swapContext.fence, VKALLOC);
        vkDestroyImageView(context.device, swapContext.attachment.view, VKALLOC);
        swapContext.fence = VK_NULL_HANDLE;
        swapContext.attachment.view = VK_NULL_HANDLE;
    }
    vkDestroySwapchainKHR(context.device, surfaceContext.swapchain, VKALLOC);
    vkDestroySemaphore(context.device, surfaceContext.imageAvailable, VKALLOC);
    vkDestroySemaphore(context.device, surfaceContext.renderingFinished, VKALLOC);
    vkDestroySurfaceKHR(context.instance, surfaceContext.surface, VKALLOC);
    vkDestroyImageView(context.device, surfaceContext.depth.view, VKALLOC);
    vkDestroyImage(context.device, surfaceContext.depth.image, VKALLOC);
    vkFreeMemory(context.device, surfaceContext.depth.memory, VKALLOC);
    if (context.currentSurface == &surfaceContext) {
        context.currentSurface = nullptr;
    }
}

uint32_t selectMemoryType(VulkanContext& context, uint32_t flags, VkFlags reqs) {
    for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
        if (flags & 1) {
            if ((context.memoryProperties.memoryTypes[i].propertyFlags & reqs) == reqs) {
                return i;
            }
        }
        flags >>= 1;
    }
    ASSERT_POSTCONDITION(false, "Unable to find a memory type that meets requirements.");
    return (uint32_t) ~0ul;
}

VkFormat getVkFormat(ElementType type, bool normalized) {
    using ElementType = ElementType;
    if (normalized) {
        switch (type) {
            // Single Component Types
            case ElementType::BYTE: return VK_FORMAT_R8_SNORM;
            case ElementType::UBYTE: return VK_FORMAT_R8_UNORM;
            case ElementType::SHORT: return VK_FORMAT_R16_SNORM;
            case ElementType::USHORT: return VK_FORMAT_R16_UNORM;
            // Two Component Types
            case ElementType::BYTE2: return VK_FORMAT_R8G8_SNORM;
            case ElementType::UBYTE2: return VK_FORMAT_R8G8_UNORM;
            case ElementType::SHORT2: return VK_FORMAT_R16G16_SNORM;
            case ElementType::USHORT2: return VK_FORMAT_R16G16_UNORM;
            // Three Component Types
            case ElementType::BYTE3: return VK_FORMAT_R8G8B8_SNORM;
            case ElementType::UBYTE3: return VK_FORMAT_R8G8B8_UNORM;
            case ElementType::SHORT3: return VK_FORMAT_R16G16B16_SNORM;
            case ElementType::USHORT3: return VK_FORMAT_R16G16B16_UNORM;
            // Four Component Types
            case ElementType::BYTE4: return VK_FORMAT_R8G8B8A8_SNORM;
            case ElementType::UBYTE4: return VK_FORMAT_R8G8B8A8_UNORM;
            case ElementType::SHORT4: return VK_FORMAT_R16G16B16A16_SNORM;
            case ElementType::USHORT4: return VK_FORMAT_R16G16B16A16_UNORM;
            default:
                ASSERT_POSTCONDITION(false, "Normalized format does not exist.");
                return VK_FORMAT_UNDEFINED;
        }
    }
    switch (type) {
        // Single Component Types
        case ElementType::BYTE: return VK_FORMAT_R8_SINT;
        case ElementType::UBYTE: return VK_FORMAT_R8_UINT;
        case ElementType::SHORT: return VK_FORMAT_R16_SINT;
        case ElementType::USHORT: return VK_FORMAT_R16_UINT;
        case ElementType::HALF: return VK_FORMAT_R16_SFLOAT;
        case ElementType::INT: return VK_FORMAT_R32_SINT;
        case ElementType::UINT: return VK_FORMAT_R32_UINT;
        case ElementType::FLOAT: return VK_FORMAT_R32_SFLOAT;
        // Two Component Types
        case ElementType::BYTE2: return VK_FORMAT_R8G8_SINT;
        case ElementType::UBYTE2: return VK_FORMAT_R8G8_UINT;
        case ElementType::SHORT2: return VK_FORMAT_R16G16_SINT;
        case ElementType::USHORT2: return VK_FORMAT_R16G16_UINT;
        case ElementType::HALF2: return VK_FORMAT_R16G16_SFLOAT;
        case ElementType::FLOAT2: return VK_FORMAT_R32G32_SFLOAT;
        // Three Component Types
        case ElementType::BYTE3: return VK_FORMAT_R8G8B8_SINT;
        case ElementType::UBYTE3: return VK_FORMAT_R8G8B8_UINT;
        case ElementType::SHORT3: return VK_FORMAT_R16G16B16_SINT;
        case ElementType::USHORT3: return VK_FORMAT_R16G16B16_UINT;
        case ElementType::HALF3: return VK_FORMAT_R16G16B16_SFLOAT;
        case ElementType::FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT;
        // Four Component Types
        case ElementType::BYTE4: return VK_FORMAT_R8G8B8A8_SINT;
        case ElementType::UBYTE4: return VK_FORMAT_R8G8B8A8_UINT;
        case ElementType::SHORT4: return VK_FORMAT_R16G16B16A16_SINT;
        case ElementType::USHORT4: return VK_FORMAT_R16G16B16A16_UINT;
        case ElementType::HALF4: return VK_FORMAT_R16G16B16A16_SFLOAT;
        case ElementType::FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT;
    }
    return VK_FORMAT_UNDEFINED;
}

VkFormat getVkFormat(TextureFormat format) {
    using TextureFormat = TextureFormat;
    switch (format) {
        // 8 bits per element.
        case TextureFormat::R8:                return VK_FORMAT_R8_UNORM;
        case TextureFormat::R8_SNORM:          return VK_FORMAT_R8_SNORM;
        case TextureFormat::R8UI:              return VK_FORMAT_R8_UINT;
        case TextureFormat::R8I:               return VK_FORMAT_R8_SINT;
        case TextureFormat::STENCIL8:          return VK_FORMAT_S8_UINT;

        // 16 bits per element.
        case TextureFormat::R16F:              return VK_FORMAT_R16_SFLOAT;
        case TextureFormat::R16UI:             return VK_FORMAT_R16_UINT;
        case TextureFormat::R16I:              return VK_FORMAT_R16_SINT;
        case TextureFormat::RG8:               return VK_FORMAT_R8G8_UNORM;
        case TextureFormat::RG8_SNORM:         return VK_FORMAT_R8G8_SNORM;
        case TextureFormat::RG8UI:             return VK_FORMAT_R8G8_UINT;
        case TextureFormat::RG8I:              return VK_FORMAT_R8G8_SINT;
        case TextureFormat::RGB565:            return VK_FORMAT_R5G6B5_UNORM_PACK16;
        case TextureFormat::RGB5_A1:           return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
        case TextureFormat::RGBA4:             return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
        case TextureFormat::DEPTH16:           return VK_FORMAT_D16_UNORM;

        // 24 bits per element. In practice, very few GPU vendors support these. For simplicity
        // we just assume they are not supported, not bothering to query the device capabilities.
        // Note that VK_FORMAT_ enums for 24-bit formats exist, but are meant for vertex attributes.
        case TextureFormat::RGB8:
        case TextureFormat::SRGB8:
        case TextureFormat::RGB8_SNORM:
        case TextureFormat::RGB8UI:
        case TextureFormat::RGB8I:
        case TextureFormat::DEPTH24:
            return VK_FORMAT_UNDEFINED;

        // 32 bits per element.
        case TextureFormat::R32F:              return VK_FORMAT_R32_SFLOAT;
        case TextureFormat::R32UI:             return VK_FORMAT_R32_UINT;
        case TextureFormat::R32I:              return VK_FORMAT_R32_SINT;
        case TextureFormat::RG16F:             return VK_FORMAT_R16G16_SFLOAT;
        case TextureFormat::RG16UI:            return VK_FORMAT_R16G16_UINT;
        case TextureFormat::RG16I:             return VK_FORMAT_R16G16_SINT;
        case TextureFormat::R11F_G11F_B10F:    return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
        case TextureFormat::RGB9_E5:           return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32;
        case TextureFormat::RGBA8:             return VK_FORMAT_R8G8B8A8_UNORM;
        case TextureFormat::SRGB8_A8:          return VK_FORMAT_R8G8B8A8_SRGB;
        case TextureFormat::RGBA8_SNORM:       return VK_FORMAT_R8G8B8A8_SNORM;
        case TextureFormat::RGBM:              return VK_FORMAT_R8G8B8A8_UNORM;
        case TextureFormat::RGB10_A2:          return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
        case TextureFormat::RGBA8UI:           return VK_FORMAT_R8G8B8A8_UINT;
        case TextureFormat::RGBA8I:            return VK_FORMAT_R8G8B8A8_SINT;
        case TextureFormat::DEPTH32F:          return VK_FORMAT_D32_SFLOAT;
        case TextureFormat::DEPTH24_STENCIL8:  return VK_FORMAT_D24_UNORM_S8_UINT;
        case TextureFormat::DEPTH32F_STENCIL8: return VK_FORMAT_D32_SFLOAT_S8_UINT;

        // 48 bits per element. Note that many GPU vendors do not support these.
        case TextureFormat::RGB16F:            return VK_FORMAT_R16G16B16_SFLOAT;
        case TextureFormat::RGB16UI:           return VK_FORMAT_R16G16B16_UINT;
        case TextureFormat::RGB16I:            return VK_FORMAT_R16G16B16_SINT;

        // 64 bits per element.
        case TextureFormat::RG32F:             return VK_FORMAT_R32G32_SFLOAT;
        case TextureFormat::RG32UI:            return VK_FORMAT_R32G32_UINT;
        case TextureFormat::RG32I:             return VK_FORMAT_R32G32_SINT;
        case TextureFormat::RGBA16F:           return VK_FORMAT_R16G16B16A16_SFLOAT;
        case TextureFormat::RGBA16UI:          return VK_FORMAT_R16G16B16A16_UINT;
        case TextureFormat::RGBA16I:           return VK_FORMAT_R16G16B16A16_SINT;

        // 96-bits per element.
        case TextureFormat::RGB32F:            return VK_FORMAT_R32G32B32_SFLOAT;
        case TextureFormat::RGB32UI:           return VK_FORMAT_R32G32B32_UINT;
        case TextureFormat::RGB32I:            return VK_FORMAT_R32G32B32_SINT;

        // 128-bits per element
        case TextureFormat::RGBA32F:           return VK_FORMAT_R32G32B32A32_SFLOAT;
        case TextureFormat::RGBA32UI:          return VK_FORMAT_R32G32B32A32_UINT;
        case TextureFormat::RGBA32I:           return VK_FORMAT_R32G32B32A32_SINT;

        default:
            return VK_FORMAT_UNDEFINED;
    }
}

uint32_t getBytesPerPixel(TextureFormat format) {
    return details::FTexture::getFormatSize(format);
}

// See also FTexture::computeTextureDataSize, which takes a public-facing Texture format rather
// than a driver-level Texture format, and can account for a specified byte alignment.
uint32_t computeSize(TextureFormat format, uint32_t w, uint32_t h, uint32_t d) {
    const size_t bytesPerTexel = details::FTexture::getFormatSize(format);
    return bytesPerTexel * w * h * d;
}

SwapContext& getSwapContext(VulkanContext& context) {
    VulkanSurfaceContext& surface = *context.currentSurface;
    return surface.swapContexts[surface.currentSwapIndex];
}

bool hasPendingWork(VulkanContext& context) {
    if (context.pendingWork.size() > 0) {
        return true;
    }
    if (context.currentSurface) {
        for (auto& swapContext : context.currentSurface->swapContexts) {
            if (swapContext.pendingWork.size() > 0) {
                return true;
            }
        }
    }
    return false;
}

VkCompareOp getCompareOp(SamplerCompareFunc func) {
    using Compare = driver::SamplerCompareFunc;
    switch (func) {
        case Compare::LE: return VK_COMPARE_OP_LESS_OR_EQUAL;
        case Compare::GE: return VK_COMPARE_OP_GREATER_OR_EQUAL;
        case Compare::L:  return VK_COMPARE_OP_LESS;
        case Compare::G:  return VK_COMPARE_OP_GREATER;
        case Compare::E:  return VK_COMPARE_OP_EQUAL;
        case Compare::NE: return VK_COMPARE_OP_NOT_EQUAL;
        case Compare::A:  return VK_COMPARE_OP_ALWAYS;
        case Compare::N:  return VK_COMPARE_OP_NEVER;
    }
}

VkBlendFactor getBlendFactor(BlendFunction mode) {
    using BlendFunction = filament::driver::BlendFunction;
    switch (mode) {
        case BlendFunction::ZERO:                  return VK_BLEND_FACTOR_ZERO;
        case BlendFunction::ONE:                   return VK_BLEND_FACTOR_ONE;
        case BlendFunction::SRC_COLOR:             return VK_BLEND_FACTOR_SRC_COLOR;
        case BlendFunction::ONE_MINUS_SRC_COLOR:   return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
        case BlendFunction::DST_COLOR:             return VK_BLEND_FACTOR_DST_COLOR;
        case BlendFunction::ONE_MINUS_DST_COLOR:   return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
        case BlendFunction::SRC_ALPHA:             return VK_BLEND_FACTOR_SRC_ALPHA;
        case BlendFunction::ONE_MINUS_SRC_ALPHA:   return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
        case BlendFunction::DST_ALPHA:             return VK_BLEND_FACTOR_DST_ALPHA;
        case BlendFunction::ONE_MINUS_DST_ALPHA:   return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
        case BlendFunction::SRC_ALPHA_SATURATE:    return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
    }
}

void waitForIdle(VulkanContext& context) {
    // If there's no valid GPU then we have nothing to do.
    if (!context.device) {
        return;
    }

    // If there's no surface, then there's no command buffer.
    if (!context.currentSurface) {
        return;
    }

    // First, wait for submitted command buffer(s) to finish.
    VkFence fences[2];
    uint32_t nfences = 0;
    auto& surfaceContext = *context.currentSurface;
    for (auto& swapContext : surfaceContext.swapContexts) {
        assert(nfences < 2);
        if (swapContext.submitted && swapContext.fence) {
            fences[nfences++] = swapContext.fence;
            swapContext.submitted = false;
        }
    }
    if (nfences > 0) {
        vkWaitForFences(context.device, nfences, fences, VK_FALSE, ~0ull);
    }

    // If we don't have any pending work, we're done.
    if (!hasPendingWork(context)) {
        return;
    }

    // We cannot invoke arbitrary commands inside a render pass.
    assert(context.currentRenderPass.renderPass == VK_NULL_HANDLE);

    // Create a one-off command buffer to avoid the cost of swap chain acquisition and to avoid
    // the possibility of SURFACE_LOST. Note that Vulkan command buffers use the Allocate/Free
    // model instead of Create/Destroy and are therefore okay to create at a high frequency.
    VkCommandBuffer cmdbuffer;
    VkFence fence;
    VkCommandBufferBeginInfo beginInfo { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
    VkCommandBufferAllocateInfo allocateInfo = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
        .commandPool = context.commandPool,
        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
        .commandBufferCount = 1
    };
    VkFenceCreateInfo fenceCreateInfo { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, };
    vkAllocateCommandBuffers(context.device, &allocateInfo, &cmdbuffer);
    vkCreateFence(context.device, &fenceCreateInfo, VKALLOC, &fence);

    // Keep performing work until there's nothing queued up. This should never iterate more than
    // a couple times because the only work we queue up is for resource transition / reclamation.
    VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
    VkSubmitInfo submitInfo {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .pWaitDstStageMask = &waitDestStageMask,
        .commandBufferCount = 1,
        .pCommandBuffers = &cmdbuffer,
    };
    int cycles = 0;
    while (hasPendingWork(context)) {
        if (cycles++ > 2) {
            utils::slog.e << "Unexpected daisychaining of pending work." << utils::io::endl;
            break;
        }
        for (auto& swapContext : context.currentSurface->swapContexts) {
            vkBeginCommandBuffer(cmdbuffer, &beginInfo);
            performPendingWork(context, swapContext, cmdbuffer);
            vkEndCommandBuffer(cmdbuffer);
            vkQueueSubmit(context.graphicsQueue, 1, &submitInfo, fence);
            vkWaitForFences(context.device, 1, &fence, VK_FALSE, UINT64_MAX);
            vkResetFences(context.device, 1, &fence);
            vkResetCommandBuffer(cmdbuffer, 0);
        }
    }
    vkFreeCommandBuffers(context.device, context.commandPool, 1, &cmdbuffer);
    vkDestroyFence(context.device, fence, VKALLOC);
}

void acquireCommandBuffer(VulkanContext& context) {
    // Ask Vulkan for the next image in the swap chain and update the currentSwapIndex.
    VulkanSurfaceContext& surface = *context.currentSurface;
    VkResult result = vkAcquireNextImageKHR(context.device, surface.swapchain,
            UINT64_MAX, surface.imageAvailable, VK_NULL_HANDLE, &surface.currentSwapIndex);
    ASSERT_POSTCONDITION(result != VK_ERROR_OUT_OF_DATE_KHR,
            "Stale / resized swap chain not yet supported.");
    ASSERT_POSTCONDITION(result == VK_SUBOPTIMAL_KHR || result == VK_SUCCESS,
            "vkAcquireNextImageKHR error.");
    SwapContext& swap = getSwapContext(context);

    // Ensure that the previous submission of this command buffer has finished.
    result = vkWaitForFences(context.device, 1, &swap.fence, VK_FALSE, UINT64_MAX);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkWaitForFences error.");

    // Restart the command buffer.
    result = vkResetFences(context.device, 1, &swap.fence);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkResetFences error.");
    VkCommandBuffer cmdbuffer = swap.cmdbuffer;
    VkResult error = vkResetCommandBuffer(cmdbuffer, 0);
    ASSERT_POSTCONDITION(not error, "vkResetCommandBuffer error.");
    VkCommandBufferBeginInfo beginInfo {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
    };
    error = vkBeginCommandBuffer(cmdbuffer, &beginInfo);
    ASSERT_POSTCONDITION(not error, "vkBeginCommandBuffer error.");
    context.cmdbuffer = cmdbuffer;
    swap.submitted = false;
}

void releaseCommandBuffer(VulkanContext& context) {
    // Finalize the command buffer and set the cmdbuffer pointer to null.
    VkResult result = vkEndCommandBuffer(context.cmdbuffer);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkEndCommandBuffer error.");
    context.cmdbuffer = nullptr;

    // Submit the command buffer.
    VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
    VulkanSurfaceContext& surfaceContext = *context.currentSurface;
    SwapContext& swapContext = getSwapContext(context);
    VkSubmitInfo submitInfo {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .waitSemaphoreCount = 1u,
        .pWaitSemaphores = &surfaceContext.imageAvailable,
        .pWaitDstStageMask = &waitDestStageMask,
        .commandBufferCount = 1,
        .pCommandBuffers = &swapContext.cmdbuffer,
        .signalSemaphoreCount = 1u,
        .pSignalSemaphores = &surfaceContext.renderingFinished,
    };
    result = vkQueueSubmit(context.graphicsQueue, 1, &submitInfo, swapContext.fence);
    ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkQueueSubmit error.");
    swapContext.submitted = true;
}

void performPendingWork(VulkanContext& context, SwapContext& swapContext, VkCommandBuffer cmdbuf) {
    // First, execute pending tasks that are specific to this swap context. Copy the tasks into a
    // local queue first, which allows newly added tasks to be deferred until the next frame.
    decltype(swapContext.pendingWork) tasks;
    tasks.swap(swapContext.pendingWork);
    for (auto& callback : tasks) {
        callback(cmdbuf);
    }
    // Next, execute the global pending work. Again, we copy the work queue into a local queue
    // to allow tasks to re-add themselves.
    tasks.clear();
    tasks.swap(context.pendingWork);
    for (auto& callback : tasks) {
        callback(cmdbuf);
    }
}

// Flushes the command buffer and waits for it to finish executing. Useful for diagnosing
// sychronization issues.
void flushCommandBuffer(VulkanContext& context) {
    VulkanSurfaceContext& surface = *context.currentSurface;
    const SwapContext& sc = surface.swapContexts[surface.currentSwapIndex];

    // Submit the command buffer.
    VkResult error = vkEndCommandBuffer(context.cmdbuffer);
    ASSERT_POSTCONDITION(!error, "vkEndCommandBuffer error.");
    VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
    VkSubmitInfo submitInfo {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .pWaitDstStageMask = &waitDestStageMask,
        .commandBufferCount = 1,
        .pCommandBuffers = &context.cmdbuffer,
    };
    error = vkQueueSubmit(context.graphicsQueue, 1, &submitInfo, sc.fence);
    ASSERT_POSTCONDITION(!error, "vkQueueSubmit error.");

    // Restart the command buffer.
    error = vkWaitForFences(context.device, 1, &sc.fence, VK_FALSE, UINT64_MAX);
    ASSERT_POSTCONDITION(!error, "vkWaitForFences error.");
    error = vkResetFences(context.device, 1, &sc.fence);
    ASSERT_POSTCONDITION(!error, "vkResetFences error.");
    error = vkResetCommandBuffer(context.cmdbuffer, 0);
    ASSERT_POSTCONDITION(!error, "vkResetCommandBuffer error.");
    VkCommandBufferBeginInfo beginInfo {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
    };
    error = vkBeginCommandBuffer(context.cmdbuffer, &beginInfo);
    ASSERT_POSTCONDITION(!error, "vkBeginCommandBuffer error.");
}

VkFormat findSupportedFormat(VulkanContext& context, const std::vector<VkFormat>& candidates,
        VkImageTiling tiling, VkFormatFeatureFlags features) {
    for (VkFormat format : candidates) {
        VkFormatProperties props;
        vkGetPhysicalDeviceFormatProperties(context.physicalDevice, format, &props);
        if (tiling == VK_IMAGE_TILING_LINEAR &&
                (props.linearTilingFeatures & features) == features) {
            return format;
        } else if (tiling == VK_IMAGE_TILING_OPTIMAL &&
                (props.optimalTilingFeatures & features) == features) {
            return format;
        }
    }
    return VK_FORMAT_UNDEFINED;
}

} // namespace filament
} // namespace driver
/*
 * Create a semaphore.
 * Params:
 *   state->ebx - user address of name of semaphore
 *   state->ecx - length of semaphore name
 *   state->edx - initial semaphore count
 * Returns: the global semaphore id
 */
static int Sys_CreateSemaphore(struct Interrupt_State* state)
{
	return createSemaphore(state->ebx, state->ecx, state->edx);
}
Exemple #13
0
// **********************************************************************
// **********************************************************************
// create task
int createTask(char* name,						// task name
					int (*task)(int, char**),	// task address
					int priority,				// task priority
					int argc,					// task argument count
					char* argv[])				// task argument pointers
{
	int tid;

	// find an open tcb entry slot
	for (tid = 0; tid < MAX_TASKS; tid++)
	{
		if (tcb[tid].name == 0)
		{
			char buf[8];

			// create task semaphore
			if (taskSems[tid]) deleteSemaphore(&taskSems[tid]);
			sprintf(buf, "task%d", tid);
			taskSems[tid] = createSemaphore(buf, 0, 0);
			taskSems[tid]->taskNum = 0;	// assign to shell

			// copy task name
			tcb[tid].name = (char*)malloc(strlen(name)+1);
			strcpy(tcb[tid].name, name);

			// set task address and other parameters
			tcb[tid].taskTime = 0;				// SCOTT - p5
			tcb[tid].task = task;			// task address
			tcb[tid].state = S_NEW;			// NEW task state
			tcb[tid].priority = priority;	// task priority
			tcb[tid].parent = curTask;		// parent
			tcb[tid].argc = argc;			// argument count

			// SCOTT malloc new argv parameters

			char** mallocdArgv = malloc(sizeof(char*) * MAX_ARGS);

			int i;
			for (i = 0; i < argc; i++) {
				mallocdArgv[i] = malloc(sizeof(char) * MAX_ARG_LENGTH); // max arg length = 50
				strcpy(mallocdArgv[i], argv[i]);
			}

			tcb[tid].argv = mallocdArgv;			// argument pointers			// change this line

			// end malloc SCOTT

			tcb[tid].event = 0;				// suspend semaphore

			// SCOTT - set RPT
			//tcb[tid].RPT = 0;					// root page table (project 5) 4??
			tcb[tid].RPT = LC3_RPT + ((tid) ? ((tid - 1) << 6) : 0); // from slide 35

			tcb[tid].cdir = CDIR;			// inherit parent cDir (project 6)
			
			// define task signals
			createTaskSigHandlers(tid);

			// Each task must have its own stack and stack pointer.
			tcb[tid].stack = malloc(STACK_SIZE * sizeof(int));

			// ?? may require inserting task into "ready" queue
			enqueue(readyQueue, tid, tcb[tid].priority); // SCOTT

			if (tid) swapTask();				// do context switch (if not cli)
			return tid;							// return tcb index (curTask)
		}
	}
	// tcb full!
	return -1;
} // end createTask
Exemple #14
0
// **********************************************************************
// **********************************************************************
// create task
int createTask(char* name,						// task name
		int (*task)(int, char**),	// task address
		int priority,				// task priority
		int argc,					// task argument count
		char* argv[])				// task argument pointers
{
	int tid;

	// find an open tcb entry slot
	for (tid = 0; tid < MAX_TASKS; tid++)
	{
		if (tcb[tid].name == 0)
		{
			int i = 0;
			char** newArgv = malloc(argc * sizeof(char*));
			for(i = 0; i < argc; i++)
			{
				newArgv[i] = malloc(sizeof(char) * (strlen(argv[i]) + 1));
				strcpy(newArgv[i], argv[i]);
			}


			char buf[8];

			// create task semaphore
			if (taskSems[tid]) deleteSemaphore(&taskSems[tid]);
			sprintf(buf, "task%d", tid);
			taskSems[tid] = createSemaphore(buf, 0, 0);
			taskSems[tid]->taskNum = 0;	// assign to shell

			// copy task name
			tcb[tid].name = (char*)malloc(strlen(name)+1);
			strcpy(tcb[tid].name, name);

			// set task address and other parameters
			tcb[tid].task = task;			// task address
			tcb[tid].state = S_NEW;			// NEW task state
			tcb[tid].priority = priority;	// task priority
			tcb[tid].time = 0;	// time
			tcb[tid].parent = curTask;		// parent
			//printf("\nCurTask: %d, Name: %s", curTask, tcb[curTask].name);
			//printf("\nNewTask: %d, Name: %s", tid, tcb[tid].name);
			tcb[tid].argc = argc;			// argument count

			// ?? malloc new argv parameters
			tcb[tid].argv = newArgv;			// argument pointers
			tcb[tid].event = 0;				// suspend semaphore
			tcb[tid].RPT = 0x2440;//(tid - 1) * 64 + 0x2400;	// root page table (project 5)
			tcb[tid].cdir = CDIR;			// inherit parent cDir (project 6)

			// signals
			tcb[tid].signal = 0;
			if (tid)
			{
				// inherit parent signal handlers
				tcb[tid].sigContHandler = tcb[curTask].sigContHandler;			// task mySIGCONT handler
				tcb[tid].sigIntHandler = tcb[curTask].sigIntHandler;			// mySIGINT handler
				tcb[tid].sigTermHandler = tcb[curTask].sigTermHandler;			// task mySIGTERM handler
				tcb[tid].sigTstpHandler = tcb[curTask].sigTstpHandler;			// task mySIGTSTP handler
			}
			else
			{
				// otherwise use defaults
				tcb[tid].sigContHandler = defaultSigContHandler;			// task mySIGINT handler
				tcb[tid].sigIntHandler = defaultSigIntHandler;			// task mySIGINT handler
				tcb[tid].sigTermHandler = defaultSigTermHandler;			// task mySIGINT handler
				tcb[tid].sigTstpHandler = defaultSigTstpHandler;			// task mySIGINT handler
			}

			// Each task must have its own stack and stack pointer.
			tcb[tid].stack = malloc(STACK_SIZE * sizeof(int));

			// ?? may require inserting task into "ready" queue

			enqueue(tid, &READY_QUEUE);

			if (tid) swapTask();				// do context switch (if not cli)
			return tid;							// return tcb index (curTask)
		}
	}
	// tcb full!
	return -1;
} // end createTask
Exemple #15
0
// **********************************************************************
// **********************************************************************
// OS startup
//
// 1. Init OS
// 2. Define reset longjmp vector
// 3. Define global system semaphores
// 4. Create CLI task
// 5. Enter scheduling/idle loop
//
int main(int argc, char* argv[])
{
	// All the 'powerDown' invocations must occur in the 'main'
	// context in order to facilitate 'killTask'.  'killTask' must
	// free any stack memory associated with current known tasks.  As
	// such, the stack context must be one not associated with a task.
	// The proper method is to longjmp to the 'reset_context' that
	// restores the stack for 'main' and then invoke the 'powerDown'
	// sequence.

	// save context for restart (a system reset would return here...)
	int resetCode = setjmp(reset_context);
	superMode = TRUE;						// supervisor mode

	switch (resetCode)
	{
	case POWER_DOWN_QUIT:				// quit
		powerDown(0);
		printf("\nGoodbye!!");
		return 0;

	case POWER_DOWN_RESTART:			// restart
		powerDown(resetCode);
		printf("\nRestarting system...\n");
		break;

	case POWER_UP:						// startup
		break;

	default:
		printf("\nShutting down due to error %d", resetCode);
		powerDown(resetCode);
		return 0;
	}

	// output header message
	printf("%s", STARTUP_MSG);

	// initalize OS
	initOS();

	// create global/system semaphores here
	//?? vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

	charReady = createSemaphore("charReady", BINARY, 0);
	inBufferReady = createSemaphore("inBufferReady", BINARY, 0);
	keyboard = createSemaphore("keyboard", BINARY, 1);
	tics1sec = createSemaphore("tics1sec", COUNTING, 0);
	tics10thsec = createSemaphore("tics10thsec", COUNTING, 0);
	tics10sec = createSemaphore("tics10sec", COUNTING, 0);
	dcChange = createSemaphore("dcChange", BINARY, 0);

	//?? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	// schedule CLI task
	createTask("myShell",			// task name
			P1_shellTask,	// task
			MED_PRIORITY	,	// task priority
			argc,			// task arg count
			argv);			// task argument pointers

	// HERE WE GO................

	// Scheduling loop
	// 1. Check for asynchronous events (character inputs, timers, etc.)
	// 2. Choose a ready task to schedule
	// 3. Dispatch task
	// 4. Loop (forever!)

	while(1)									// scheduling loop
	{
		// check for character / timer interrupts
		pollInterrupts();

		// schedule highest priority ready task
		if ((curTask = scheduler()) < 0) continue;

		// dispatch curTask, quit OS if negative return
		if (dispatcher() < 0) break;
	}											// end of scheduling loop

	// exit os
	longjmp(reset_context, POWER_DOWN_QUIT);
	return 0;
} // end main