Vulkan: Build a yarn::Scheduler and pass it down to the vk::Queue.

Nothing is actually scheduled, but is a first step towards using yarn.

As yarn is now actually used by SwiftShader, drop the BUILD_YARN build
flags, as failing to build yarn would result in linker errors.

Bug: b/139142453
Change-Id: Ibd9a69f72a248f58a62bb41eeb196c4647876e82
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35153
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7162fb6..551290a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,8 +79,6 @@
 endif()
 set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release MinSizeRel RelWithDebInfo)
 
-option(BUILD_YARN "Build yarn" 0)
-
 option(BUILD_EGL "Build the EGL library" 1)
 option(BUILD_GLESv2 "Build the OpenGL ES 2 library" 1)
 option(BUILD_GLES_CM "Build the OpenGL ES 1.1 library" 1)
@@ -1754,23 +1752,21 @@
     ${CMAKE_CURRENT_SOURCE_DIR}/include/vulkan/*.h}
 )
 
-if(BUILD_YARN)
-    file(GLOB YARN_FULL_LIST
-        ${YARN_DIR}/*.cpp
-        ${YARN_DIR}/*.hpp
-        ${YARN_DIR}/*.c
-    )
+file(GLOB YARN_FULL_LIST
+    ${YARN_DIR}/*.cpp
+    ${YARN_DIR}/*.hpp
+    ${YARN_DIR}/*.c
+)
 
-    if (NOT MSVC)
-        file(GLOB YARN_ASSEMBLY_LIST ${YARN_DIR}/*.S)
-        list(APPEND YARN_FULL_LIST ${YARN_ASSEMBLY_LIST})
-    endif(NOT MSVC)
+if (NOT MSVC)
+    file(GLOB YARN_ASSEMBLY_LIST ${YARN_DIR}/*.S)
+    list(APPEND YARN_FULL_LIST ${YARN_ASSEMBLY_LIST})
+endif(NOT MSVC)
 
-    set(YARN_LIST ${YARN_FULL_LIST})
-    set(YARN_TEST_LIST ${YARN_FULL_LIST})
-    list(FILTER YARN_LIST EXCLUDE REGEX ".*_test\\..*")
-    list(FILTER YARN_TEST_LIST INCLUDE REGEX ".*_test\\..*")
-endif(BUILD_YARN)
+set(YARN_LIST ${YARN_FULL_LIST})
+set(YARN_TEST_LIST ${YARN_FULL_LIST})
+list(FILTER YARN_LIST EXCLUDE REGEX ".*_test\\..*")
+list(FILTER YARN_TEST_LIST INCLUDE REGEX ".*_test\\..*")
 
 ###########################################################
 # Append OS specific files to lists
@@ -1860,16 +1856,14 @@
 # SwiftShader Targets
 ###########################################################
 
-if(BUILD_YARN)
-    add_library(Yarn STATIC ${YARN_LIST})
-    set_target_properties(Yarn PROPERTIES
-        POSITION_INDEPENDENT_CODE 1
-        FOLDER "Core"
-        COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS}"
-        COMPILE_DEFINITIONS "NO_SANITIZE_FUNCTION=;"
-    )
-    target_link_libraries(Yarn ${OS_LIBS})
-endif(BUILD_YARN)
+add_library(Yarn STATIC ${YARN_LIST})
+set_target_properties(Yarn PROPERTIES
+    POSITION_INDEPENDENT_CODE 1
+    FOLDER "Core"
+    COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS}"
+    COMPILE_DEFINITIONS "NO_SANITIZE_FUNCTION=;"
+)
+target_link_libraries(Yarn ${OS_LIBS})
 
 add_library(SwiftShader STATIC ${SWIFTSHADER_LIST})
 set_target_properties(SwiftShader PROPERTIES
@@ -2046,7 +2040,7 @@
     endif()
 
     set_shared_library_export_map(libvk_swiftshader ${SOURCE_DIR}/Vulkan)
-    target_link_libraries(libvk_swiftshader ${Reactor} ${OS_LIBS} SPIRV-Tools SPIRV-Tools-opt)
+    target_link_libraries(libvk_swiftshader ${Reactor} Yarn ${OS_LIBS} SPIRV-Tools SPIRV-Tools-opt)
     add_custom_command(
         TARGET libvk_swiftshader
         POST_BUILD
@@ -2167,7 +2161,8 @@
     endif()
 endif(BUILD_TESTS)
 
-if(BUILD_TESTS AND BUILD_YARN)
+if(BUILD_TESTS)
+    # Yarn unit tests
     file(GLOB YARN_TEST_LIST
         ${YARN_DIR}/*_test.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/third_party/googletest/googletest/src/gtest-all.cc
@@ -2189,9 +2184,8 @@
     )
 
     target_link_libraries(yarn-unittests Yarn ${OS_LIBS})
-endif(BUILD_TESTS AND BUILD_YARN)
 
-if(BUILD_TESTS)
+    # Math unit tests
     set(MATH_UNITTESTS_LIST
         ${CMAKE_CURRENT_SOURCE_DIR}/tests/MathUnitTests/main.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/tests/MathUnitTests/unittests.cpp
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 692db75..4ef1ee5 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -57,7 +57,7 @@
 	cache.updateConstCache();
 }
 
-Device::Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures)
+Device::Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, yarn::Scheduler *scheduler)
 	: physicalDevice(physicalDevice),
 	  queues(reinterpret_cast<Queue*>(mem)),
 	  enabledExtensionCount(pCreateInfo->enabledExtensionCount),
@@ -76,7 +76,7 @@
 
 		for(uint32_t j = 0; j < queueCreateInfo.queueCount; j++, queueID++)
 		{
-			new (&queues[queueID]) Queue(this);
+			new (&queues[queueID]) Queue(this, scheduler);
 		}
 	}
 
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 809ef2f..24ed2c2 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -21,6 +21,11 @@
 #include <memory>
 #include <mutex>
 
+namespace yarn
+{
+	class Scheduler;
+}
+
 namespace sw
 {
 	class Blitter;
@@ -37,7 +42,7 @@
 public:
 	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }
 
-	Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures);
+	Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, yarn::Scheduler *scheduler);
 	void destroy(const VkAllocationCallbacks* pAllocator);
 
 	static size_t ComputeRequiredAllocationSize(const VkDeviceCreateInfo* pCreateInfo);
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 31c0ebf..0efde4c 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -22,6 +22,8 @@
 #include "Pipeline/ComputeProgram.hpp"
 #include "Pipeline/SpirvShader.hpp"
 
+#include "Yarn/Trace.hpp"
+
 #include "spirv-tools/optimizer.hpp"
 
 #include <iostream>
@@ -257,6 +259,8 @@
 
 std::shared_ptr<sw::ComputeProgram> createProgram(const vk::PipelineCache::ComputeProgramKey& key)
 {
+	YARN_SCOPED_EVENT("createProgram");
+
 	vk::DescriptorSet::Bindings descriptorSets;  // FIXME(b/129523279): Delay code generation until invoke time.
 	// TODO(b/119409619): use allocator.
 	auto program = std::make_shared<sw::ComputeProgram>(key.getShader(), key.getLayout(), descriptorSets);
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
index e654ca0..329847d 100644
--- a/src/Vulkan/VkQueue.cpp
+++ b/src/Vulkan/VkQueue.cpp
@@ -19,6 +19,11 @@
 #include "WSI/VkSwapchainKHR.hpp"
 #include "Device/Renderer.hpp"
 
+#include "Yarn/Defer.hpp"
+#include "Yarn/Scheduler.hpp"
+#include "Yarn/Thread.hpp"
+#include "Yarn/Trace.hpp"
+
 #include <cstring>
 
 namespace
@@ -74,9 +79,9 @@
 namespace vk
 {
 
-Queue::Queue(Device* device) : device(device)
+Queue::Queue(Device* device, yarn::Scheduler *scheduler) : device(device)
 {
-	queueThread = std::thread(&Queue::taskLoop, this);
+	queueThread = std::thread(&Queue::taskLoop, this, scheduler);
 }
 
 Queue::~Queue()
@@ -155,8 +160,12 @@
 	}
 }
 
-void Queue::taskLoop()
+void Queue::taskLoop(yarn::Scheduler* scheduler)
 {
+	yarn::Thread::setName("Queue<%p>", this);
+	scheduler->bind();
+	defer(scheduler->unbind());
+
 	while(true)
 	{
 		Task task = pending.take();
diff --git a/src/Vulkan/VkQueue.hpp b/src/Vulkan/VkQueue.hpp
index 6d5913e..c137d15 100644
--- a/src/Vulkan/VkQueue.hpp
+++ b/src/Vulkan/VkQueue.hpp
@@ -22,6 +22,11 @@
 
 #include "System/Synchronization.hpp"
 
+namespace yarn
+{
+	class Scheduler;
+}
+
 namespace sw
 {
 	class Context;
@@ -39,7 +44,7 @@
 	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
 
 public:
-	Queue(Device* device);
+	Queue(Device* device, yarn::Scheduler *scheduler);
 	~Queue();
 
 	operator VkQueue()
@@ -64,8 +69,7 @@
 		Type type = SUBMIT_QUEUE;
 	};
 
-	static void TaskLoop(vk::Queue* queue);
-	void taskLoop();
+	void taskLoop(yarn::Scheduler* scheduler);
 	void garbageCollect();
 	void submitQueue(const Task& task);
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 2e6879c..4a71cc5 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -64,6 +64,11 @@
 
 #include "Reactor/Nucleus.hpp"
 
+#include "Yarn/Scheduler.hpp"
+#include "Yarn/Thread.hpp"
+
+#include "System/CPUID.hpp"
+
 #include <algorithm>
 #include <cstring>
 #include <string>
@@ -102,12 +107,33 @@
 	rr::Nucleus::adjustDefaultConfig(cfg);
 }
 
+void setCPUDefaults()
+{
+	sw::CPUID::setEnableSSE4_1(true);
+	sw::CPUID::setEnableSSSE3(true);
+	sw::CPUID::setEnableSSE3(true);
+	sw::CPUID::setEnableSSE2(true);
+	sw::CPUID::setEnableSSE(true);
+}
+
+yarn::Scheduler* getOrCreateScheduler()
+{
+	static auto scheduler = std::unique_ptr<yarn::Scheduler>(new yarn::Scheduler());
+	scheduler->setThreadInitializer([] {
+		sw::CPUID::setFlushToZero(true);
+		sw::CPUID::setDenormalsAreZero(true);
+	});
+	scheduler->setWorkerThreadCount(std::min<size_t>(yarn::Thread::numLogicalCPUs(), 16));
+	return scheduler.get();
+}
+
 // initializeLibrary() is called by vkCreateInstance() to perform one-off global
 // initialization of the swiftshader driver.
 void initializeLibrary()
 {
 	static bool doOnce = [] {
 		setReactorDefaultConfig();
+		setCPUDefaults();
 		return true;
 	}();
 	(void)doOnce;
@@ -563,7 +589,8 @@
 		(void)queueFamilyPropertyCount; // Silence unused variable warning
 	}
 
-	return vk::DispatchableDevice::Create(pAllocator, pCreateInfo, pDevice, vk::Cast(physicalDevice), enabledFeatures);
+	auto scheduler = getOrCreateScheduler();
+	return vk::DispatchableDevice::Create(pAllocator, pCreateInfo, pDevice, vk::Cast(physicalDevice), enabledFeatures, scheduler);
 }
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator)
diff --git a/tests/kokoro/gcp_ubuntu/continuous.sh b/tests/kokoro/gcp_ubuntu/continuous.sh
index 8800710..0021c2f 100644
--- a/tests/kokoro/gcp_ubuntu/continuous.sh
+++ b/tests/kokoro/gcp_ubuntu/continuous.sh
@@ -15,7 +15,7 @@
   REACTOR_BACKEND="LLVM"
 fi
 
-cmake .. "-DREACTOR_BACKEND=${REACTOR_BACKEND}" "-DREACTOR_VERIFY_LLVM_IR=1" "-DBUILD_YARN=1"
+cmake .. "-DREACTOR_BACKEND=${REACTOR_BACKEND}" "-DREACTOR_VERIFY_LLVM_IR=1"
 make --jobs=$(nproc)
 
 # Run unit tests
diff --git a/tests/kokoro/gcp_windows/continuous.bat b/tests/kokoro/gcp_windows/continuous.bat
index e6dc2ec..0bd0196 100644
--- a/tests/kokoro/gcp_windows/continuous.bat
+++ b/tests/kokoro/gcp_windows/continuous.bat
@@ -17,7 +17,7 @@
 cd %SRC%\build
 if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL!
 
-cmake .. -G "Visual Studio 15 2017 Win64" -Thost=x64 "-DREACTOR_BACKEND=%REACTOR_BACKEND%" "-DREACTOR_VERIFY_LLVM_IR=1" "-DBUILD_YARN=1"
+cmake .. -G "Visual Studio 15 2017 Win64" -Thost=x64 "-DREACTOR_BACKEND=%REACTOR_BACKEND%" "-DREACTOR_VERIFY_LLVM_IR=1"
 if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL!
 
 %MSBUILD% /p:Configuration=%CONFIG% SwiftShader.sln
diff --git a/tests/kokoro/macos/continuous.sh b/tests/kokoro/macos/continuous.sh
index 8d7a92b..ca1ae26 100755
--- a/tests/kokoro/macos/continuous.sh
+++ b/tests/kokoro/macos/continuous.sh
@@ -15,7 +15,7 @@
   REACTOR_BACKEND="LLVM"
 fi
 
-cmake .. "-DASAN=ON" "-DREACTOR_BACKEND=${REACTOR_BACKEND}" "-DCMAKE_BUILD_TYPE=RelWithDebInfo" "-DREACTOR_VERIFY_LLVM_IR=1" "-DBUILD_YARN=1"
+cmake .. "-DASAN=ON" "-DREACTOR_BACKEND=${REACTOR_BACKEND}" "-DCMAKE_BUILD_TYPE=RelWithDebInfo" "-DREACTOR_VERIFY_LLVM_IR=1"
 make -j$(sysctl -n hw.logicalcpu)
 
 # Run unit tests