Merge pull request #153 from shadps4-emu/small_additions
video_core: multiple render targets binding
This commit is contained in:
commit
ff21750815
|
@ -321,9 +321,13 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
|
||||||
case Opcode::V_MAX_F32:
|
case Opcode::V_MAX_F32:
|
||||||
translator.V_MAX_F32(inst);
|
translator.V_MAX_F32(inst);
|
||||||
break;
|
break;
|
||||||
|
case Opcode::V_RSQ_F32:
|
||||||
|
translator.V_RSQ_F32(inst);
|
||||||
|
break;
|
||||||
case Opcode::S_ANDN2_B64:
|
case Opcode::S_ANDN2_B64:
|
||||||
translator.S_ANDN2_B64(inst);
|
translator.S_ANDN2_B64(inst);
|
||||||
break;
|
break;
|
||||||
|
case Opcode::S_NOP:
|
||||||
case Opcode::S_CBRANCH_EXECZ:
|
case Opcode::S_CBRANCH_EXECZ:
|
||||||
case Opcode::S_CBRANCH_SCC0:
|
case Opcode::S_CBRANCH_SCC0:
|
||||||
case Opcode::S_MOV_B64:
|
case Opcode::S_MOV_B64:
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
void V_FMA_F32(const GcnInst& inst);
|
void V_FMA_F32(const GcnInst& inst);
|
||||||
void V_CMP_F32(ConditionOp op, const GcnInst& inst);
|
void V_CMP_F32(ConditionOp op, const GcnInst& inst);
|
||||||
void V_MAX_F32(const GcnInst& inst);
|
void V_MAX_F32(const GcnInst& inst);
|
||||||
|
void V_RSQ_F32(const GcnInst& inst);
|
||||||
|
|
||||||
// Vector Memory
|
// Vector Memory
|
||||||
void BUFFER_LOAD_FORMAT(u32 num_dwords, bool is_typed, const GcnInst& inst);
|
void BUFFER_LOAD_FORMAT(u32 num_dwords, bool is_typed, const GcnInst& inst);
|
||||||
|
|
|
@ -193,4 +193,9 @@ void Translator::V_MAX_F32(const GcnInst& inst) {
|
||||||
SetDst(inst.dst[0], ir.FPMax(src0, src1));
|
SetDst(inst.dst[0], ir.FPMax(src0, src1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Translator::V_RSQ_F32(const GcnInst& inst) {
|
||||||
|
const IR::F32 src0{GetSrc(inst.src[0], true)};
|
||||||
|
SetDst(inst.dst[0], ir.FPRecipSqrt(src0));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader::Gcn
|
} // namespace Shader::Gcn
|
||||||
|
|
|
@ -416,6 +416,10 @@ struct Liverpool {
|
||||||
BitField<20, 4, u32> output5_mask;
|
BitField<20, 4, u32> output5_mask;
|
||||||
BitField<24, 4, u32> output6_mask;
|
BitField<24, 4, u32> output6_mask;
|
||||||
BitField<28, 4, u32> output7_mask;
|
BitField<28, 4, u32> output7_mask;
|
||||||
|
|
||||||
|
[[nodiscard]] u8 GetMask(int buf_id) const {
|
||||||
|
return (raw >> (buf_id * 4)) & 0xffu;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IndexBufferBase {
|
struct IndexBufferBase {
|
||||||
|
@ -631,6 +635,10 @@ struct Liverpool {
|
||||||
u32 clear_word1;
|
u32 clear_word1;
|
||||||
INSERT_PADDING_WORDS(2);
|
INSERT_PADDING_WORDS(2);
|
||||||
|
|
||||||
|
operator bool() const {
|
||||||
|
return info.format != DataFormat::FormatInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
u32 Pitch() const {
|
u32 Pitch() const {
|
||||||
return (pitch.tile_max + 1) << 3;
|
return (pitch.tile_max + 1) << 3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
vk::DynamicState::eBlendConstants,
|
vk::DynamicState::eBlendConstants,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (instance.IsColorWriteEnableSupported()) {
|
||||||
|
dynamic_states.push_back(vk::DynamicState::eColorWriteEnableEXT);
|
||||||
|
dynamic_states.push_back(vk::DynamicState::eColorWriteMaskEXT);
|
||||||
|
}
|
||||||
|
|
||||||
const vk::PipelineDynamicStateCreateInfo dynamic_info = {
|
const vk::PipelineDynamicStateCreateInfo dynamic_info = {
|
||||||
.dynamicStateCount = static_cast<u32>(dynamic_states.size()),
|
.dynamicStateCount = static_cast<u32>(dynamic_states.size()),
|
||||||
.pDynamicStates = dynamic_states.data(),
|
.pDynamicStates = dynamic_states.data(),
|
||||||
|
@ -144,18 +149,21 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 shader_count = 2;
|
u32 shader_count = 1;
|
||||||
std::array<vk::PipelineShaderStageCreateInfo, MaxShaderStages> shader_stages;
|
std::array<vk::PipelineShaderStageCreateInfo, MaxShaderStages> shader_stages;
|
||||||
shader_stages[0] = vk::PipelineShaderStageCreateInfo{
|
shader_stages[0] = vk::PipelineShaderStageCreateInfo{
|
||||||
.stage = vk::ShaderStageFlagBits::eVertex,
|
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||||
.module = modules[0],
|
.module = modules[0],
|
||||||
.pName = "main",
|
.pName = "main",
|
||||||
};
|
};
|
||||||
|
if (modules[4]) {
|
||||||
shader_stages[1] = vk::PipelineShaderStageCreateInfo{
|
shader_stages[1] = vk::PipelineShaderStageCreateInfo{
|
||||||
.stage = vk::ShaderStageFlagBits::eFragment,
|
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||||
.module = modules[4],
|
.module = modules[4],
|
||||||
.pName = "main",
|
.pName = "main",
|
||||||
};
|
};
|
||||||
|
++shader_count;
|
||||||
|
}
|
||||||
|
|
||||||
const auto it = std::ranges::find(key.color_formats, vk::Format::eUndefined);
|
const auto it = std::ranges::find(key.color_formats, vk::Format::eUndefined);
|
||||||
const u32 num_color_formats = std::distance(key.color_formats.begin(), it);
|
const u32 num_color_formats = std::distance(key.color_formats.begin(), it);
|
||||||
|
@ -177,8 +185,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
.srcAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.alpha_src_factor),
|
.srcAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.alpha_src_factor),
|
||||||
.dstAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.color_dst_factor),
|
.dstAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.color_dst_factor),
|
||||||
.alphaBlendOp = LiverpoolToVK::BlendOp(control.alpha_func),
|
.alphaBlendOp = LiverpoolToVK::BlendOp(control.alpha_func),
|
||||||
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
.colorWriteMask =
|
||||||
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
instance.IsColorWriteEnableSupported()
|
||||||
|
? vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||||
|
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA
|
||||||
|
: key.write_masks[i],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct GraphicsPipelineKey {
|
||||||
Liverpool::PolygonMode polygon_mode;
|
Liverpool::PolygonMode polygon_mode;
|
||||||
Liverpool::CullMode cull_mode;
|
Liverpool::CullMode cull_mode;
|
||||||
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
||||||
|
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
|
||||||
|
|
||||||
bool operator==(const GraphicsPipelineKey& key) const noexcept {
|
bool operator==(const GraphicsPipelineKey& key) const noexcept {
|
||||||
return std::memcmp(this, &key, sizeof(GraphicsPipelineKey)) == 0;
|
return std::memcmp(this, &key, sizeof(GraphicsPipelineKey)) == 0;
|
||||||
|
@ -66,6 +67,10 @@ public:
|
||||||
return key.stage_hashes[0] == EmbeddedVsHash;
|
return key.stage_hashes[0] == EmbeddedVsHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto GetWriteMasks() const {
|
||||||
|
return key.write_masks;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BuildDescSetLayout();
|
void BuildDescSetLayout();
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ bool Instance::CreateDevice() {
|
||||||
vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT,
|
vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT,
|
||||||
vk::PhysicalDeviceFragmentShaderInterlockFeaturesEXT,
|
vk::PhysicalDeviceFragmentShaderInterlockFeaturesEXT,
|
||||||
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT,
|
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT,
|
||||||
|
vk::PhysicalDeviceColorWriteEnableFeaturesEXT,
|
||||||
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR>();
|
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR>();
|
||||||
const vk::StructureChain properties_chain =
|
const vk::StructureChain properties_chain =
|
||||||
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
|
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
|
||||||
|
@ -152,6 +153,9 @@ bool Instance::CreateDevice() {
|
||||||
index_type_uint8 = add_extension(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME);
|
index_type_uint8 = add_extension(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME);
|
||||||
add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
||||||
|
// The next two extensions are required to be available together in order to support write masks
|
||||||
|
color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
|
||||||
|
color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||||
|
|
||||||
const auto family_properties = physical_device.getQueueFamilyProperties();
|
const auto family_properties = physical_device.getQueueFamilyProperties();
|
||||||
if (family_properties.empty()) {
|
if (family_properties.empty()) {
|
||||||
|
@ -191,6 +195,7 @@ bool Instance::CreateDevice() {
|
||||||
vk::PhysicalDeviceFeatures2{
|
vk::PhysicalDeviceFeatures2{
|
||||||
.features{
|
.features{
|
||||||
.robustBufferAccess = features.robustBufferAccess,
|
.robustBufferAccess = features.robustBufferAccess,
|
||||||
|
.independentBlend = true,
|
||||||
.geometryShader = features.geometryShader,
|
.geometryShader = features.geometryShader,
|
||||||
.logicOp = features.logicOp,
|
.logicOp = features.logicOp,
|
||||||
.samplerAnisotropy = features.samplerAnisotropy,
|
.samplerAnisotropy = features.samplerAnisotropy,
|
||||||
|
@ -216,12 +221,23 @@ bool Instance::CreateDevice() {
|
||||||
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{
|
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{
|
||||||
.indexTypeUint8 = true,
|
.indexTypeUint8 = true,
|
||||||
},
|
},
|
||||||
|
vk::PhysicalDeviceColorWriteEnableFeaturesEXT{
|
||||||
|
.colorWriteEnable = true,
|
||||||
|
},
|
||||||
|
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{
|
||||||
|
.extendedDynamicState3ColorWriteMask = true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!index_type_uint8) {
|
if (!index_type_uint8) {
|
||||||
device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>();
|
device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!color_write_en) {
|
||||||
|
device_chain.unlink<vk::PhysicalDeviceColorWriteEnableFeaturesEXT>();
|
||||||
|
device_chain.unlink<vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT>();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
device = physical_device.createDeviceUnique(device_chain.get());
|
device = physical_device.createDeviceUnique(device_chain.get());
|
||||||
} catch (vk::ExtensionNotPresentError& err) {
|
} catch (vk::ExtensionNotPresentError& err) {
|
||||||
|
|
|
@ -111,6 +111,11 @@ public:
|
||||||
return external_memory_host;
|
return external_memory_host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true when VK_EXT_color_write_enable is supported
|
||||||
|
bool IsColorWriteEnableSupported() const {
|
||||||
|
return color_write_en;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the vendor ID of the physical device
|
/// Returns the vendor ID of the physical device
|
||||||
u32 GetVendorID() const {
|
u32 GetVendorID() const {
|
||||||
return properties.vendorID;
|
return properties.vendorID;
|
||||||
|
@ -218,6 +223,7 @@ private:
|
||||||
bool fragment_shader_barycentric{};
|
bool fragment_shader_barycentric{};
|
||||||
bool shader_stencil_export{};
|
bool shader_stencil_export{};
|
||||||
bool external_memory_host{};
|
bool external_memory_host{};
|
||||||
|
bool color_write_en{};
|
||||||
u64 min_imported_host_pointer_alignment{};
|
u64 min_imported_host_pointer_alignment{};
|
||||||
bool tooling_info{};
|
bool tooling_info{};
|
||||||
bool debug_utils_supported{};
|
bool debug_utils_supported{};
|
||||||
|
|
|
@ -93,17 +93,26 @@ void PipelineCache::RefreshGraphicsKey() {
|
||||||
key.stencil_ref_back = regs.stencil_ref_back;
|
key.stencil_ref_back = regs.stencil_ref_back;
|
||||||
key.prim_type = regs.primitive_type;
|
key.prim_type = regs.primitive_type;
|
||||||
key.polygon_mode = regs.polygon_control.PolyMode();
|
key.polygon_mode = regs.polygon_control.PolyMode();
|
||||||
key.blend_controls = regs.blend_control;
|
|
||||||
|
|
||||||
const auto& db = regs.depth_buffer;
|
const auto& db = regs.depth_buffer;
|
||||||
key.depth_format = key.depth.depth_enable
|
key.depth_format = key.depth.depth_enable
|
||||||
? LiverpoolToVK::DepthFormat(db.z_info.format, db.stencil_info.format)
|
? LiverpoolToVK::DepthFormat(db.z_info.format, db.stencil_info.format)
|
||||||
: vk::Format::eUndefined;
|
: vk::Format::eUndefined;
|
||||||
for (u32 i = 0; i < Liverpool::NumColorBuffers; i++) {
|
// `RenderingInfo` is assumed to be initialized with a contiguous array of valid color
|
||||||
const auto& cb = regs.color_buffers[i];
|
// attachments. This might be not a case as HW color buffers can be bound in an arbitrary order.
|
||||||
key.color_formats[i] = cb.base_address
|
// We need to do some arrays compaction at this stage
|
||||||
? LiverpoolToVK::SurfaceFormat(cb.info.format, cb.NumFormat())
|
int remapped_cb{};
|
||||||
: vk::Format::eUndefined;
|
for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) {
|
||||||
|
auto const& col_buf = regs.color_buffers[cb];
|
||||||
|
if (!col_buf) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
key.color_formats[remapped_cb] =
|
||||||
|
LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat());
|
||||||
|
key.blend_controls[remapped_cb] = regs.blend_control[cb];
|
||||||
|
key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)};
|
||||||
|
|
||||||
|
++remapped_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < MaxShaderStages; i++) {
|
for (u32 i = 0; i < MaxShaderStages; i++) {
|
||||||
|
|
|
@ -39,14 +39,21 @@ void Rasterizer::Draw(bool is_indexed) {
|
||||||
const GraphicsPipeline* pipeline = pipeline_cache.GetGraphicsPipeline();
|
const GraphicsPipeline* pipeline = pipeline_cache.GetGraphicsPipeline();
|
||||||
pipeline->BindResources(memory, vertex_index_buffer, texture_cache);
|
pipeline->BindResources(memory, vertex_index_buffer, texture_cache);
|
||||||
|
|
||||||
const auto& image_view = texture_cache.RenderTarget(regs.color_buffers[0]);
|
boost::container::static_vector<vk::RenderingAttachmentInfo, Liverpool::NumColorBuffers>
|
||||||
|
color_attachments{};
|
||||||
|
for (const auto& col_buf : regs.color_buffers) {
|
||||||
|
if (!col_buf) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto& image_view = texture_cache.RenderTarget(col_buf);
|
||||||
|
|
||||||
const vk::RenderingAttachmentInfo color_info = {
|
color_attachments.push_back({
|
||||||
.imageView = *image_view.image_view,
|
.imageView = *image_view.image_view,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
.loadOp = vk::AttachmentLoadOp::eLoad,
|
.loadOp = vk::AttachmentLoadOp::eLoad,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Don't restart renderpass every draw
|
// TODO: Don't restart renderpass every draw
|
||||||
const auto& scissor = regs.screen_scissor;
|
const auto& scissor = regs.screen_scissor;
|
||||||
|
@ -57,11 +64,11 @@ void Rasterizer::Draw(bool is_indexed) {
|
||||||
.extent = {scissor.GetWidth(), scissor.GetHeight()},
|
.extent = {scissor.GetWidth(), scissor.GetHeight()},
|
||||||
},
|
},
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
.colorAttachmentCount = 1,
|
.colorAttachmentCount = static_cast<u32>(color_attachments.size()),
|
||||||
.pColorAttachments = &color_info,
|
.pColorAttachments = color_attachments.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdateDynamicState();
|
UpdateDynamicState(*pipeline);
|
||||||
|
|
||||||
cmdbuf.beginRendering(rendering_info);
|
cmdbuf.beginRendering(rendering_info);
|
||||||
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->Handle());
|
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->Handle());
|
||||||
|
@ -125,12 +132,22 @@ u32 Rasterizer::SetupIndexBuffer(bool& is_indexed) {
|
||||||
return regs.num_indices;
|
return regs.num_indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rasterizer::UpdateDynamicState() {
|
void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
|
||||||
UpdateViewportScissorState();
|
UpdateViewportScissorState();
|
||||||
|
|
||||||
auto& regs = liverpool->regs;
|
auto& regs = liverpool->regs;
|
||||||
const auto cmdbuf = scheduler.CommandBuffer();
|
const auto cmdbuf = scheduler.CommandBuffer();
|
||||||
cmdbuf.setBlendConstants(®s.blend_constants.red);
|
cmdbuf.setBlendConstants(®s.blend_constants.red);
|
||||||
|
|
||||||
|
if (instance.IsColorWriteEnableSupported()) {
|
||||||
|
const auto& write_masks = pipeline.GetWriteMasks();
|
||||||
|
std::array<vk::Bool32, Liverpool::NumColorBuffers> write_ens{};
|
||||||
|
std::transform(write_masks.cbegin(), write_masks.cend(), write_ens.begin(),
|
||||||
|
[](auto in) { return in ? vk::True : vk::False; });
|
||||||
|
|
||||||
|
cmdbuf.setColorWriteEnableEXT(write_ens);
|
||||||
|
cmdbuf.setColorWriteMaskEXT(0, write_masks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rasterizer::UpdateViewportScissorState() {
|
void Rasterizer::UpdateViewportScissorState() {
|
||||||
|
|
|
@ -37,7 +37,7 @@ private:
|
||||||
u32 SetupIndexBuffer(bool& is_indexed);
|
u32 SetupIndexBuffer(bool& is_indexed);
|
||||||
void MapMemory(VAddr addr, size_t size);
|
void MapMemory(VAddr addr, size_t size);
|
||||||
|
|
||||||
void UpdateDynamicState();
|
void UpdateDynamicState(const GraphicsPipeline& pipeline);
|
||||||
void UpdateViewportScissorState();
|
void UpdateViewportScissorState();
|
||||||
void UpdateDepthStencilState();
|
void UpdateDepthStencilState();
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#define PAGE_NOACCESS PROT_NONE
|
#define PAGE_NOACCESS PROT_NONE
|
||||||
#define PAGE_READWRITE (PROT_READ | PROT_WRITE)
|
#define PAGE_READWRITE (PROT_READ | PROT_WRITE)
|
||||||
|
#define PAGE_READONLY PROT_READ
|
||||||
#else
|
#else
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue